Search code examples
c#nhibernatesession-managementnancy

How should NHibernate session be handled in Nancy for session-per-request?


Really, my my question is in the title... How should NHibernate session be handled in Nancy for session-per-request? If you've got a good answer for that in and of itself, go for it... if you need more background, here it is:


I am accustomed to using an actionFilter in ASP.NET MVC to open and close a session in the NHibernate context at the beginning and end of a web request. That way, each database operation within the context of a request uses the same session.

I thought I had the same kind of thing set up in my new project that uses Nancy, but every time a session is needed, a new one is generated. Here's how I'm handling the opening and closing of session in my bootstrapper (inheriting from StructureMapBootstrapper):

protected override void RequestStartup(IContainer container, IPipelines pipelines, NancyContext context)
{
    var sessionContainer = container.GetInstance<ISessionContainer>();
    pipelines.BeforeRequest.AddItemToStartOfPipeline(x =>
    {
        sessionContainer.OpenSession();
        return x.Response;
    });
    pipelines.AfterRequest.AddItemToEndOfPipeline(x => sessionContainer.CloseSession());
}

My ISessionContainer is based off of something similar to this site. My implementation of ISessionContainer uses NHibernate's session context to get the "current session".

Right now, when I try this in my Nancy project, a new session is returned each time the ISessionContainer.Session property is requested. I thought it was because cookie-based sessions are not enabled by default in Nancy, so I added this to my bootstrapper:

protected override void ApplicationStartup(IContainer container, IPipelines pipelines)
{
    CookieBasedSessions.Enable(pipelines);
}

No dice. I'm still given a new session every time ask for one.

But, really, I don't want to diagnose my problem. I'd rather hear what is the standard way to handle NHibernate session management in Nancy.


Solution

  • In my Nancy port of the RestBucks sample I use NHibernate in a seesion per request fashion.

    In the bootstrapper from that sample I have the following setup of NHibernate:

    protected override void ApplicationStartup(IWindsorContainer container, 
                                               Nancy.Bootstrapper.IPipelines pipelines)
    {
      base.ApplicationStartup(container, pipelines);
      pipelines.BeforeRequest += ctx => CreateSession(container);
      pipelines.AfterRequest += ctx => CommitSession(container);
      pipelines.OnError += (ctx, ex) => RollbackSession(container);
      // Other startup stuff 
    }
    
    private Response CreateSession(IWindsorContainer container)
    {
      var sessionFactory = container.Resolve<ISessionFactory>();
      var requestSession = sessionFactory.OpenSession();
      CurrentSessionContext.Bind(requestSession);
      requestSession.BeginTransaction();
    
      return null;
    }
    
    private AfterPipeline CommitSession(IWindsorContainer container)
    {
      var sessionFactory = container.Resolve<ISessionFactory>();
      if (CurrentSessionContext.HasBind(sessionFactory))
      {
        var requestSession = sessionFactory.GetCurrentSession();
        requestSession.Transaction.Commit();
        CurrentSessionContext.Unbind(sessionFactory);
        requestSession.Dispose();
      }
      return null;
     }    
    
    private Response RollbackSession(IWindsorContainer container)
    {
      var sessionFactory = container.Resolve<ISessionFactory>();
      if (CurrentSessionContext.HasBind(sessionFactory))
      {
        var requestSession = sessionFactory.GetCurrentSession();
        requestSession.Transaction.Rollback();
        CurrentSessionContext.Unbind(sessionFactory);
        requestSession.Dispose();
      }
      return null;
    }
    

    Exactly how you want to setup your NHibernate session will likely differ.