views:

414

answers:

2

Does anyone have any tips or best practices regarding how Autofac can help manage the NHibernate ISession Instance (in the case of an ASP.NET MVC application)?

A: 

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.

James L
*Why* isn't that a good idea?
Peter Lillevold
Agree with James on this, I inject a unit of work factory into my (asp.net mvc) controllers and create a unit of work from inside the controller when required. The factory is just wrapper class (service locator) around the IoC container (Structure Map)
AWC
I don't agree, because ... (missing)
Paco
@AWC: thats exactly what I would do too. Thing is that the Autofac container gives you the factory stuff OOTB.
Peter Lillevold
Hi James, I believe that AutoFac provides HttpRequestScoped(), which I think will provide the same behaviour as the http module. I might be wrong, but I think one benefit is that this will only new up the object in requests that actually used it, rather than on all requests as you would get with the HttpModule.
UpTheCreek
Thanks for the tip re generic error handling and rolling back - will bear in mind!
UpTheCreek
@UpTheCreek. Interesting - I've never used Autofac before. It sounds like that'll work, as long is it calls Dispose for you.
James L
+5  A: 

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.

Peter Lillevold
Hmm... I wish people would give some constructive criticism when they downvote.
Peter Lillevold
Me too! :) Thanks for your answer - I'm taking a look into your suggestions
UpTheCreek
Hi, I understand everything here appart from the Func<Owned<Isession>> - Why use this? Why not just inject into the standard ISession? I'm not sure I really understand what the func/Owned does, but according to the autofac documentation, if you use it you have to dispose of the object manually? <quote>A component that gains references to Owned<T> is responsible for calling Owned<T>.Dispose when the instance is no longer required. It is a bug to not clean up owned instances.</quote> http://code.google.com/p/autofac/wiki/NewInV2
UpTheCreek
@UpTheCreek - see my update. Hopefully it clarifies my idea :)
Peter Lillevold