Edit: If you’re on the trunk version of NServiceBus there is a better way to manage the session using the child container feature.

This post explains how to manage the NHibernate session when using NServiceBus. In NServiceBus each message becomes a unit of work so the recommendation is to use a new session for each message that gets processed. NServiceBus wraps the handling of each message in a TransactionScope. This scope becomes the unit of work and guarantees consistency between the data store and the underlying queuing technology. Note that this requires the endpoint to be configured as "transactional", the default in NServiceBus.

Configuring the session factory
First we have to configure the NHibernate session factory so that we can create new sessions. Creating a session factory is an expensive operation so we need configure it as a singleton.

ISessionFactory sessionFactory = ConfigureSessionFactory();            Configure.Instance.Configurer.RegisterSingleton(typeof(ISessionFactory), sessionFactory);

Creating and managing a session per request can be done in a number of ways so lets start with the simplest one.

Explicitly create the session in each handler

This brute force way is to open and use the session in each of your message handlers. An example of this is shown below

public class SaveToDatabaseUsingRawSessionHandler : IHandleMessages<SaveToDatabaseUsingRawSession>    {        private readonly ISessionFactory sessionFactory;

        public SaveToDatabaseUsingRawSessionHandler(ISessionFactory sessionFactory)        {            this.sessionFactory = sessionFactory;        }

        public void Handle(SaveToDatabaseUsingRawSession message)        {            // the session will automatically enlist in the TransactionScope            // that NServiceBus wraps calls to messagehandlers in (given that the endpoint            // is configured as "transactional")            using (var session = sessionFactory.OpenSession())            {                session.Save(new PersistentEntity { Data = message.DataToPersist });            }        }    }

The fact that NServiceBus wraps message handling in a TransactionScope means that NHibernate will automatically enlist and commit or rollback accordingly. The drawback with this solution is that you need to duplicate the call to create a session in all of your message handlers. If you use some kind of repository pattern you would have to explicitly pass the session to all those repositories in order to have them use the same session. Let's see how we can improve this a bit.

Storing the session in the NHibernate session context

To avoid duplicate code and having to pass the ISession around we can use the context session feature in NHibernate to store our session for the duration of the request. To do this we need a way to create a new session and store it in the session context when message processing begins. This is done using the message module feature in NServiceBus. Message modules are created by implementing the IMessageModule interface. NServiceBus will then automatically detect those classes and invoke them at the various stages of the message processing pipeline.

With this solution the code in our message handler is reduced to this:

public class SaveToDatabaseUsingMessageModuleHandler : IHandleMessages<SaveToDatabaseUsingMessageModule>   {      private  readonly  ISessionFactory  sessionFactory;      public  SaveToDatabaseUsingMessageModuleHandler(ISessionFactory  sessionFactory)      {          this.sessionFactory = sessionFactory;      }

      public void Handle(SaveToDatabaseUsingMessageModule message)       {           sessionFactory.GetCurrentSession().Save(new PersistentEntity { Data = message.DataToPersist });       }   }

And the message module is implemented like this:

 public class NHibernateMessageModule : IMessageModule   {       private readonly ISessionFactory sessionFactory;

       public NHibernateMessageModule(ISessionFactory sessionFactory)       {           this.sessionFactory = sessionFactory;       }

       public void HandleBeginMessage()       {           CurrentSessionContext.Bind(sessionFactory.OpenSession());       }

       public void HandleEndMessage()       {          //session is closed when the transactionscope is disposed so we           //don't have to do anything here       }

       public void HandleError()       {       }   }

Note that in order for this to work the NHibernate session context mode needs to be thread_static. A sample of how to configure the session factory can be found here.

Managing the session using your favorite IoC container

This solution is equivalent to the one above but relies on the thread static cache mode of your container of choice. This example uses StructureMap if you prefer one of the other supported containers please use the syntax of that container. Also note that this solution doesn't require a message module to open the session.

In order to get this to work we just configure the container to create a new ISession for each thread and cache it thread static. This means that we can change our repositories and message handlers to depend on ISession directly and let the container do it's magic. The container will then make sure that all code executed on the same thread will use the same ISession.

The container configuration looks like this:

ObjectFactory.Configure(x=>                            {                                x.For<ISession>().CacheBy(InstanceScope .ThreadLocal)                                    .Use(ctx => ctx.GetInstance<ISessionFactory>().OpenSession());

                            });

A sample message handler is seen below

public   class   SaveToDatabaseUsingContainerCacheModeHandler :  IHandleMessages< SaveToDatabaseUsingContainerCacheMode>{    private  readonly  ISession  session;

    public  SaveToDatabaseUsingContainerCacheModeHandler(ISession  session)    {        this.session = session;    }

     public   void  Handle( SaveToDatabaseUsingContainerCacheMode message)     {        session.Save(new  PersistentEntity  { Data = message.DataToPersist });    }}

This solution basically replaces the caching provided by NHibernate with the one provided by the container, with the added benefit of not needing the message module.

Edit:

To have the session recreated for each thread you'd have to implement your own StructureMap lifecycle.

Summary

NHibernate sessions in NServiceBus should be used on a "per message basis". Hopefully this post will give you ideas on how you can best solve this in your application. Running endpoints non-transactional is not recommended and should only be used under special circumstances. If you do need non transactional endpoints remember that you have to manage the NHibernate transaction your self!

A full sample can be found here.

As always comments/suggestions are most welcome!