Managing NHibernate ISession with Autofac
Does anyone have any tips or best practices regarding how Autofac can help manage t开发者_StackOverflow社区he NHibernate ISession Instance (in the case of an ASP.NET MVC application)?
I'm not overly familiar with how NHibernate sessions should be handled. That said, Autofac have excellent instance lifetime handling (scoping and deterministic disposal). Some related resources are this article and this question. Since you're in ASP.Net MVC land make sure you also look into the MVC integration stuff.
To illustrate the point, here's a quick sample on how you can use Autofac factory delegates and the Owned
generic to get full control over instance lifetime:
public class SomeController
{
private readonly Func<Owned<ISession>> _sessionFactory;
public SomeController(Func<Owned<ISession>> sessionFactory)
{
_sessionFactory = sessionFactory;
}
public void DoSomeWork()
{
using (var session = _sessionFactory())
{
var transaction = session.Value.BeginTransaction();
....
}
}
}
The container setup to get this to work is quite simple. Notice that we don't have to do anything to get the Func<>
and Owned<>
types, these are made available automatically by Autofac:
builder.Register(c => cfg.BuildSessionFactory())
.As<ISessionFactory>()
.SingleInstance();
builder.Register(c => c.Resolve<ISessionFactory>().OpenSession());
Update: my reasoning here is that, according to this NHibernate tutorial, the lifetime of the session instance should be that of the "unit of work". Thus we need some way of controlling both when the session instance is created and when the session is disposed.
With Autofac we get this control by requesting a Func<>
instead of the type directly. Not using Func<>
would require that the session instance be created upfront before the controller instance is created.
Next, the default in Autofac is that instances have the lifetime of their container. Since we know that we need the power to dispose this instance as soon as the unit of work is done, we request an Owned
instance. Disposing the owned instance will in this case immediately dispose the underlying session.
Edit: Sounds like Autofac and probably other containers can scope the lifetime correctly. If that's the case, go for it.
It isn't a good idea to use your IoC container to manage sessions directly. The lifetime of your session should correspond to your unit of work (transaction boundary). In the case of a web application, that should almost certainly be the lifetime of a web request.
The most common way to achieve this is with an HttpModule that both creates your session and starts your transaction when a request begins, then commits when the request has finished. I would have the HttpModule register the session in the HttpContext.Items collection.
In your IoC container, you could register something like HttpContextSessionLocator against ISessionLocator.
I should mention that your generic error handling should locate the current session and roll back the transaction automatically, or you could end up committing half a unit of work.
精彩评论