Because of its simplicity, the most common pattern used in web applications for managing NHibernate sessions is session-per-request. In this recipe, I'll show you how to set up the session-per-request pattern using NHibernate's contextual sessions feature.
NHibernate.dll
, NHibernate.ByteCode.Castle.dll
, log4net.dll
, and our Eg.Core
model and mappings project from Chapter 1.web.config
file, set up the NHibernate and log4net configuration sections. Refer to the Configuring NHibernate with App.config recipes in Chapter 2.hibernate-configuration
section of web.config
, add the current_session_context_class
property with a value of web
.Global.asax
).Global.asax
, add these using statements.using NHibernate; using NHibernate.Cfg; using NHibernate.Context;
SessionFactory
.public static ISessionFactory SessionFactory { get; private set; }
Application_Start
method, add the following code.protected void Application_Start(object sender, EventArgs e) { log4net.Config.XmlConfigurator.Configure(); var nhConfig = new Configuration().Configure(); SessionFactory = nhConfig.BuildSessionFactory(); }
Application_BeginRequest
method, add the following code.protected void Application_BeginRequest(object sender, EventArgs e) { var session = SessionFactory.OpenSession(); CurrentSessionContext.Bind(session); }
Application_EndRequest
method, add the following code:protected void Application_EndRequest(object sender, EventArgs e) { var session = CurrentSessionContext.Unbind(SessionFactory); session.Dispose(); }
In web applications, it's common to use a session for each web request. We open the session when the request begins and close it when the request ends.
NHibernate's contextual session feature allows a session to be associated with some application-specific scope that approximates a single unit of work. This context is configured with the
current_session_context_class
property, which specifies an implementation of NHibernate.Context.ICurrentSessionContext
. In this case, we'll associate it with the web request. web
is the short name for NHibernate.Context.WebSessionContext
.
Even with contextual sessions, NHibernate does not open, close or dispose the session for us. We associate and dissociate a session with the current web request using the CurrentSessionContext.Bind
and Unbind
methods.
To get the NHibernate session for the current web request, we use
SessionFactory.GetCurrentSession()
. In our example web application, it might look something like this:
Guid productId = new Guid(Request["id"]);
Eg.Core.Product product;
var session = Global.SessionFactory.GetCurrentSession();
using (var tran = session.BeginTransaction())
{
product = session.Get<Eg.Core.Product>(productId);
tran.Commit();
}
Page.Title = product.Name;
Label1.Text = product.Name;
Label2.Text = product.Description;
This naive example fetches a product from the database and displays the name and description to the user. In a production-worthy application, we would use dependency injection rather than directly access the singleton. The free TekPub Concepts screencast provides a thorough introduction to dependency injection, and can be found at http://tekpub.com/view/concepts/1.
NHibernate sessions are extremely lightweight and cheap to make. Simply opening a session doesn't open a database connection. NHibernate makes every effort to avoid any delay opening a connection. On the other hand, NHibernate goes through great effort to create the session factory. You should only create one session factory for the entire lifecycle of the application.
There are many implementations of session per request using Inversion of Control containers and even HTTP modules. Some use contextual sessions. Others manage the session without NHibernate's help. A complete session per request implementation has four characteristics: