NHibernate - Session Per Request

A common pattern when using NHibernate on web applications is to create a new session which lasts for the duration of the request. I was looking at the possibility of formalising this somehow, but that will be for another day. I'm simply going to explain my approach and post some code snippets here.

The Repository

For this particular application, I'm also using StructureMap. The data access classes take an IRepository interface in their constructor which define the following methods and property:

void Configure(string connectionString, Func<System.Collections.IDictionary> requestVariables);
void BeginSession();
void EndSession(bool commit);
ISession Session { get; }

Where ISession is the NHibernate session interface. The DAOs then simply use the Session property to perform the necessary queries.

StructureMap is configured using the default conventions and so will return the same IRepository instance for the life of the application. The implementation is pretty simple (I may put it up on GitHub at some point):

  • Configure builds the session factory.
  • BeginSession opens a new session and calls BeginTransaction on the session. The session is added into the dictionary returned by the requestVariables function (more on that below).
  • EndSession gets the session out of the requestVariables and commits or rolls-back the transactions, depending on the argument. Also, the transaction and session are cleaned-up.

HttpContext

Clearly, the function returning the IDictionary is of importance in relation to managing the session; also when the Begin/End calls are made.

In our Application_Start method, after StructureMap has been configured, we configure the repository:

ObjectFactory.GetInstance<IRepository>().Configure(
  WebConfigurationManager.ConnectionStrings[connString].ConnectionString,
  () => HttpContext.Current.Items);

The second argument is where the repository will store the session…i.e. it will use the current HttpContext's items. This dictionary is therefore going to be specific to the particular request. The reason for this indirection is two-fold (rather than directly referencing HttpContext in the Repository class). Firstly, the repository class is in a separate project, which isn't tied to the web, so can't assume a HttpContext exists. Secondly, it makes testing the repository simple, as all that's required is a function returning a dictionary.

Finishing it off

Finally, the easy part. In Application_BeginRequest we have:

ObjectFactory.GetInstance<IRepository>().BeginSession();

And in Application_EndRequest we have:

ObjectFactory.GetInstance<IRepository>().EndSession(Context.Error == null)

This gives up a reasonably simple session-per-request implementation, committing the transaction only if no errors have occurred whilst processing the request.


Comment Guidelines
See the FAQ for details on the full rules and guidelines. No Spam. Write clearly and thoughtfully - no bad language.