6

Using NHibernate with an ASP.NET MVC 3 Application

Once a company has created a database and the internal systems to control the data, it is not very difficult to use the data again with other functionality. The myGuitarStore database contains information about the types of guitars, the builder, the model, and the cost. Obviously, this information is something a potential customer would like to know before making a purchase. One of the best means of providing this information to a customer is via a website. Therefore, this chapter describes and creates a website that implements ASP.NET MVC 3 using NHibernate.

To create the website shown in Figure 6-1, you will perform the following activities:

  1. Install ASP.NET MVC 3, which deposits the MVC 3 assemblies and registers them into the Global Assembly Cache (GAC).
  2. Add an ASP.NET MVC project to the existing GuitarStore solution.
  3. Configure NHibernate and the Session solution.
  4. Configure the View and Controller.

images

FIGURE 6-1

INSTALLING ASP.NET MVC 3

ASP.NET MVC 3 is not installed with Visual Studio 2010. Therefore, you need to download it from the Microsoft website at www.asp.net/mvc/mvc3 and install it just as you would any other software package. The ASP.NET MVC 3 download used in this example is AspNetMVC3ToolsUpdateSetup.exe.

ADDING AN ASP.NET MVC 3 PROJECT TO THE GUITARSTORE SOLUTION

Open Microsoft Visual Web Developer 2010 Express and select New Project. Then select ASP.NET MVC 3 images Web Application, name it GuitarStoreMVC, and click OK. In the dialog that appears, select Internet Application, and in the View Engine drop-down, select ASPX. Click OK. Figure 6-2 shows the created project.

images

FIGURE 6-2

CONFIGURING NHIBERNATE

Several activities are required to configure NHibernate within an MVC project. In order to have an MVC project work with NHibernate and to use the NHibernate.GuitarStore library, you need to do the following:

  1. Add references to the NHibernate and NHibernate.GuitarStore binaries.
  2. Add connectionString to the Web.config file.
  3. Add the NHibernate configuration setting to the Global.asax.cs file.
  4. Configure the ASP.NET MVC 3 program to use a session-per-web-request solution.

Adding References to the Binaries

Begin by right-clicking the Reference folder and adding the NHibernate binaries, then add the NHibernate.GuitarStore.dll. Refer to Chapter 1, “Getting Started with NHibernate 3,” for more details on which NHibernate binaries are used and where they are located.

Adding connectionString to the Web.config File

Open the Web.config file found in the root directory of the MVC project. The Web.config file is modified to contain the connectionString and configuration settings used by NHibernate to connect to the myGuitarStore database. Add the code in Listing 6-1 to the Web.config file.

LISTING 6-1: MVC 3 Web.config settings
<configSections>
    <section name=“hibernate-configuration”
             type=“NHibernate.Cfg.ConfigurationSectionHandler, NHibernate” />
  </configSections>
  <hibernate-configuration xmlns=“urn:nhibernate-configuration-2.2”>
    <session-factory>
      <property name=“connection.connection_string_name”>
                          GuitarStore</property>
      <property name=“connection.provider”>
                          NHibernate.Connection.DriverConnectionProvider</property>
    </session-factory>
  </hibernate-configuration>
  <connectionStrings>
    <add name=“GuitarStore”
         connectionString=“Data Source=(local);Initial Catalog=myGuitarStore;
         Integrated Security=True”/>
  </connectionStrings>

images NOTE The connectionString provided in the preceding listing is an example only. You should modify parameters to meet your specific needs.

Next, open the Global.asax.cs file and add a static class-level SessionFactory property, as shown in Listing 6-2.

LISTING 6-2: Creating a static class-level SessionFactory
using NHibernate;

namespace GuitarStoreMVC
{
  public class MvcApplication : System.Web.HttpApplication
  {
    public static ISessionFactory SessionFactory { get; private set; }
  }
}

Then modify the Application_Start() method so that it resembles Listing 6-3.

LISTING 6-3: MVC 3 Application_Start() method
using NHibernate.Cfg;
using NHibernate.Cfg.Loquacious;
using NHibernate.Context;
using NHibernate.Dialect;
using NHibernate.Driver;
using NHibernate.GuitarStore;

protected void Application_Start()
{
   AreaRegistration.RegisterAllAreas();

   RegisterGlobalFilters(GlobalFilters.Filters);
   RegisterRoutes(RouteTable.Routes);

   var configure = new Configuration();
   configure.DataBaseIntegration(dbi =>
   {
      dbi.Dialect<MsSql2008Dialect>();
      dbi.Driver<SqlClientDriver>();
      dbi.Timeout = 10;
   });

   configure.CurrentSessionContext<WebSessionContext>();
   configure.AddAssembly(“NHibernate.GuitarStore”);

   SessionFactory = configure.BuildSessionFactory();

}

Notice that an additional setting, CurrentSessionContext, is applied to the GuitarStore WPF configuration discussed in Chapter 1. Several contexts can be used within web-based programs; the CurrentSessionContext class is being set to WebSessionContext in this GuitarStoreMVC example system. The NHibernate.Context classes provide methods to bind and unbind a Session to a context. The programmer, who is responsible for specifically defining the context of the Session, would then use the GetCurrentSession() method of the SessionFactory to retrieve the NHibernate Session used to perform transactions against the database. Table 6-1 describes the most common context classes.

TABLE 6-1:NHibernate Session Contexts

CONTEXT CLASS DESCRIPTION
ManagedWebSessionContext Works only with web programs. The HttpContext tracks the current Session. The programmer is responsible for binding and unbinding an ISession instance on this class.
WcfOperationSessionContext Works only during the lifetime of an WCF operation.
WebSessionContext Analogous to the ManagedWebSessionContext, but the ISession instance is bound and unbound using the CurrentContextSession class.
ThreadStaticSessionContext Provides a current Session if more than a single SessionFactory is used.

The context and management of a Session varies according to the type of program being created. For example, recall the session-per-presenter solution used in the GuitarStore WPF program, where the context of the Session is explicitly bound to a WPF window instead of using the CurrentSessionContext setting. The GuitarStore WPF program called for that type of implementation, whereas this ASP.NET MVC program calls for a session-per-web-request solution within a WebSessionContext context.

CONFIGURING THE ASP.NET MVC PROGRAM TO USE A SESSION-PER-WEB-REQUEST

To implement this session-per-web-request Session solution, add an Application_BeginRequest() method and an Application_EndRequest() method to the Global.asax.cs file as shown in Listing 6-4.

LISTING 6-4: Application_BeginRequest() and Application_EndRequest() methods
protected void Application_BeginRequest(object sender, EventArgs e)
{
  var session = SessionFactory.OpenSession();
  CurrentSessionContext.Bind(session);
}

protected void Application_EndRequest(object sender, EventArgs e)
{
   var session = CurrentSessionContext.Unbind(SessionFactory);
   session.Dispose();
}

The Application_BeginRequest() method is called each time a request to an ASP.NET page is processed; the method opens a Session and then binds it to the current context. When the ASP.NET request is complete, the Application_EndRequest() method is called, which unbinds the Session from the current context and disposes of it, which makes it available for garbage collection.

CONFIGURING THE VIEW AND CONTROLLER

Now that NHibernate is installed and the session management solution is implemented, the code required to view and retrieve the data can be programmed. In this section, you perform the following:

  1. Add a method named ExecuteHQL<T>() that accepts an HQL query and an ISession and returns a IList<T>.
  2. Add a method named GuitarList() to the Controller.
  3. Add a method named ExecuteCriteria<T>() that accepts an ISession and an Id search parameter and returns an IList<T>.
  4. Add a method named InventoryList() to the Controller.
  5. Modify the View to use the methods created in the Controller and present the data using jqGrid.

First, to continue with the separation of the NHibernate details from the implementation of the NHibernate query APIs, you need to create a new method within the NHibernateInventory class found in the DataAccess directory of the NHibernate.GuitarStore project. Add the method shown in Listing 6-5 to the NHibernateInventory class.

LISTING 6-5: Generic HQL method with a Session
public IList<T> ExecuteHQL<T>(string hqlQuery, ISession session)
{
  using (ITransaction transaction = session.BeginTransaction())
  {
    IQuery query = session.CreateQuery(hqlQuery);
    return query.List<T>();
  }
}

Next, configure the Controller by opening the HomeController.cs file located in the Controllers directory and add the GuitarList() method shown in Listing 6-6, which retrieves and populates the jqGrid with the Guitar data using NHibernate.

LISTING 6-6: The Controller GuitarList() method
using NHibernate;
using NHibernate.GuitarStore.Common;
using NHibernate.GuitarStore.DataAccess;

public ActionResult GuitarList(string sidx, string sord, int page, int rows)
{
  IList<Guitar> guitarList = null;

  try
  {
    NHibernateInventory nhi = new NHibernateInventory();

    var session = GuitarStoreMVC.MvcApplication.SessionFactory.GetCurrentSession();
    using (var transaction = session.BeginTransaction())
    {
      guitarList = nhi.ExecuteHQL<Guitar>(“from Guitar order by Type", session);
    }
    var jsonData = new
    {
       rows = (
          from g in guitarList
          select new
          {
            id = g.Id,
            cell = new string[] { g.Type }
          }).ToArray()
     };
     return Json(jsonData, JsonRequestBehavior.AllowGet);
   }
   catch (Exception ex)
   {
     ViewBag.Message = ex.Message;
     return View();
   }
}

The GetCurrentSession() method of the SessionFactory is used to get the Session within the previously configured context described in Listing 6-3. Then the Session is used to begin, execute, and commit the transaction that retrieves the data from the GUITAR table. Finally, the result set is converted into a Json data type using LINQ and returned.

Next, add the ExecuteCriteria<T>() method, which accepts an ISession and an Id search parameter. The code is shown in Listing 6-7.

LISTING 6-7: Generic ICriteria method with a Session
public IList<T> ExecuteCriteria<T>(ISession session, Guid Id) where T : class
{
  using (ITransaction transaction = session.BeginTransaction())
  {
    try
    {
      ICriteria criteria = session.CreateCriteria<T>()
                                  .Add(Restrictions.Eq(“TypeId”, Id));
      return criteria.List<T>();
    }
    catch (Exception ex)
    {
      transaction.Rollback();
      throw;
    }
  }
}

Next, add the InventoryList() method, which is executed when the Guitar list is expanded to the HomeController.cs file found in the Controllers directory, as shown in Listing 6-8.

LISTING 6-8: The Controller InventoryList() method
using NHibernate;
using NHibernate.GuitarStore.Common;
using NHibernate.GuitarStore.DataAccess;

public ActionResult InventoryList(string sidx, string sord, int page, int rows,
  Guid Id)
{
  IList<Inventory> inventoryList = null;

  try
  {
    NHibernateInventory nhi = new NHibernateInventory();

    var session = GuitarStoreMVC.MvcApplication.SessionFactory.GetCurrentSession();
    using (var transaction = session.BeginTransaction())
    {
      inventoryList = nhi.ExecuteCriteria<Inventory>(session, Id);
    }

    var jsonSubData = new
    {
      rows = (from i in inventoryList
              select new
              {
                id = i.Id.ToString(),
                cell = new string[] {
                i.Builder,
                i.Model,
                “$” + i.Cost.ToString()
              }
            }).ToArray()
     };

     return Json(jsonSubData, JsonRequestBehavior.AllowGet);
   }
   catch (Exception ex)
   {
     ViewBag.Message = ex.Message;
     return View();
   }
}

This method receives the Id of the guitar type that was expanded in the jqGrid. Again, the GetCurrentSession() method is called to get a Session, which is used together with the Id to retrieve the list of inventory for the requested guitar type.

Next, to begin the View configuration, open the Index.aspx file located in the ViewsHome directory and add the GuitarList function, which displays the guitar information, as shown in Listing 6-9.

LISTING 6-9: GuitarList View function
<table id=‘GuitarList’></table><div id=‘GuitarList_pager’></div>
<script type=‘text/javascript’>
   jQuery(document).ready(function () {
       jQuery(‘#GuitarList’).jqGrid({
            url: ‘/Home/GuitarList/’,
            datatype: ‘json’,
            mtype: ‘GET’,
            colNames: [‘Guitar Types’],
            colModel:
                [
                    { name: ‘TYPE’, index: ‘TYPE’, width: 60, align: ‘left’ },
                ],
            autowidth: true,
            height: ‘auto’,
            sortname: ‘TYPE’,
            sortorder: “ASC”,
            viewrecords: true,
            multiselect: false,
            subGrid: true,
            subGridRowExpanded: showDetails
        })
      jQuery(“#GuitarList”).jqGrid(‘navGrid‘, ’#GuitarList_pager‘,
            { add: false, edit: false, del: false, search: false })
    })
</script>

The preceding function uses jQuery to redirect the request to the GuitarList() method found in the ControllerHomeController.cs file. Listing 6-10 shows the function that displays the inventory based on which guitar type is expanded.

LISTING 6-10: InventoryList View function
<table id=‘InventoryList’></table><div id=‘’InventoryList‘_pager’></div>
<script type=‘text/javascript’>
    function showSubGrid_InventoryList(subgrid_id, row_id, message, suffix) {
        var subgrid_table_id, pager_id;
        subgrid_table_id = subgrid_id + ‘_t’;
        pager_id = ‘p_’ + subgrid_table_id;
        if (suffix) { subgrid_table_id += suffix; pager_id += suffix; }
        if (message) jQuery(‘#’ + subgrid_id).append(message);
         jQuery(‘#’ + subgrid_id).append(‘<table id=’ + subgrid_table_id +
            ‘ class=scroll></table><div id=’ + pager_id + ‘ class=scroll></div>’);
         jQuery(‘#’ + subgrid_table_id).jqGrid({
            url: ‘/Home/InventoryList/’ + row_id,
            datatype: ‘json’,
            colNames: [‘Builder’, ‘Model’, ‘Cost’],
            colModel:
                [
                 { name: ‘Builder’, index: ‘BUILDER’, width: 10, align: ‘left’ },
                 { name: ‘Model’, index: ‘MODEL’, width: 10, align: ‘left’ },
                 { name: ‘Cost’, index: ‘COST’, width: 10, align: ‘left’ },
                ],
            caption: ‘Inventory’,
            sortorder: “ASC”,
            width: ‘550’,
            height: ‘auto’
        })
    }
</script>

Lastly, add the showDetails function, shown in Listing 6-11, which is called from the SubGridRowExpanded event to bind the GuitarList and InventoryList together.

LISTING 6-11: The showDetail function called from subGridRowExpanded event
<script type=“text/javascript”>
    function showDetails(subgrid_id, row_id) {
         showSubGrid_InventoryList(subgrid_id, row_id, “”, “InventoryList”);
    }
</script>

images NOTE The installation and configuration of jqGrid is not discussed here, but it only requires downloading the scripts and referencing them from within the ASP.NET files. The downloadable source code contains the jqGrid library and theme.

SUMMARY

A database can be accessed from many sources and used in a number of different ways. NHibernate has the functionality to support ASP.NET, ASP.NET MVC 3, WCF, WPF, and other types of access. It is important to apply a context for the Session, whether it is a session-per-presenter, a session-per-web-request, or something else, so that the full capabilities of NHibernate can be realized.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.189.186.167