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.
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.