piotrwalat.net

NHibernate session management in ASP.NET Web API

9 comments

In this post I am going to describe a way to manage NHibernate sessions in WebAPI applications using ‘session-per-action’ pattern. This includes working NHibernate configuration that uses contextual sessions and SQL CE 4, simple model and mappings as well as some WebAPI specific bits (action filter and use of HttpConfiguration).

The problem

Accessing data using NHibernate usually consists of following steps:

  1. Creating a SessionFactory object.
  2. Opening a session.
  3. Accessing the data
  4. Closing the session

Regardless of your application type (be it a desktop or a web app) you will need a strategy to manage session lifecycle. This is no different in Web API.
Here are the most popular approaches I can think of (for web apps):

  1. create a new session every time you access data
  2. create session per each HTTP request
  3. create session per each action call (valid if using ASP.NET MVC / Web API)

Session per request

Creating sessions for each request can be accomplished by handling application’s Begin_Request and End_Request events in Global.asax.cs

This approach is quite common and there is a substantial amount of blog entries about it. The problem here is that the session will be created every time we make a HTTP request. Sometimes it may constitute a problem – for example if we serve static content (such as images) through ASP.NET pipeline – in this case the session will be created for each such request.

Going further – unauthorized calls will still cause session to be created, even though we don’t really want or need that. For example this code would still create a session (and a transaction if  you wrapped your requests in a transaction as well)

Due to these issues it may be worth to consider managing sessions within a more granular scope.

Session per action

Alternatively we can create session object in the scope of an action. In ASP.NET MVC and Web API world this means creating action filter and using it to decorate actions or controllers (which will apply it to all actions).

Its worth to mention that session-per-action makes lazy loading in views impossible, because session will be closed before view templates are rendered. Lazy loading data in your views seems like a bad habit anyway and you should rather use flattened out view models instead.

Model and mappings

Let’s start by creating a simple model that we will persist.

We also need mappings, I’m using NHibernate’s own code mapping here (quite a fresh feature), but feel free to use anything else you prefer (eg. FluentNH or xml mappings).

Configuration

Besides that we also need NHibernate config that defines among other things, connection settings. I’ve decided to use Sql Server CE 4.0, but of course you can swap it for any other db engine supported by NHibernate (such as SQL Server).

Please note that in order for SQL Compact 4 to work you may need to add qualifyAssembly entry to web.config file (otherwise NHibernate will look for 3.5 assembly).

Also note that we will be using NHibernate’s contextual sessions (current_session_context_class set to web). This will make make NHibernate use HttpContext to store current session.

In order to be able to instantiate session objects we need SessionFactory, which we are going to share among our web application (SessionFactory.GetSession() it is thread safe so no worries).

Session management action filter

Now we need to create action filter that will actually create a new session and bind it to the current context.

As a bonus we wrap actions in an explicit transaction, which is preferred over using implicit transactions.

Adding simple repository

Let’s abstract persistence layer by adding a simple repository to our project. It will use SessionFactory.GetCurrentSession() to retrieve ISession bound to current context and created by our filter.

 

Using HttpConfiguration

If you plan to use persistence layer (and sessions) in every controller of your api it may be worth leveraging WebAPI configuration capabilities to provide default behavior and eliminate need to manually decorate controllers.

 

Using it in controllers

Now we can easily use repositories and underlying session in our ApiController.

Hope this helps. You can view source code on bitbucket.org or get it using git:

git clone https://bitbucket.org/pwalat/piotrwalat.net.nhsessionmanagment.git

Written by Piotr Walat

June 4th, 2012 at 2:02 am

  • Pingback: Dew Drop – June 5, 2012 (#1,341) | Alvin Ashcraft's Morning Dew

  • http://www.krokonoster.com Krokonoster

    Hi Piotr,
    Great article, thanks.
    I’m getting a “No session bound to the current context” when I call this in my controller (will get to inject dependencies later, for now just want to make it work)

    private readonly Models.NHibernateRepository _companyRepository = new Models.NHibernateRepository();

    Any idea?

  • Krokonoster

    Hi Piotr,Great article, thanks.I’m getting a “No session bound to the current context” when I call this in my controller (will get to inject dependencies later, for now just want to make it work)
    private readonly Models.NHibernateRepository _companyRepository = new Models.NHibernateRepository();
    Any idea?

    • http://www.piotrwalat.net/ Piotr Walat

      Hmm, where do you create your repository? Is it inside of Web API controller action?
      Is the action decorated with [NhSessionManagement] attribute?

      • Andrew

        I’ve been using a similiar model of having in my base controller class a repository reference that is set on first access and in the controllers destructor a check that disposes of the repository if it’s set.  Works pretty well

  • John Wallace

    Great article.  Exactly what I was looking for.  Any ideas on how to do similar using entity framework? Thanks

  • Dcunningham

    The CitiesController.cs file is scrambled.  I’m having the same problem as Krokonoster ( ”No session bound to the current context” )

  • Vadim Rybak

    Awesome article. I really like the idea of using a global filter to manage session. However, this is problematic when using an IOC container.  If I inject the repository into the controllers constructor, I will get an error because the action filter has not fired yet. So the session has not been bound. This is because OnActionExecuting is fired after the controller is instantiated.

  • Markus Padourek

    Yeah, same for me, I can’t  read the CitiesController.cs file and getting a “No session bound to the current context”  error. Any idea how I could fix that?
    Great article though.