Search code examples
.netnhibernatehttpcontextlazy-initializationisession

Lazy initializing ISession using WebSessionContext/CurrentSessionContext


I'm starting a new project with NHibernate 3 and I'm trying to use the CurrentSessionContext API with WebSessionContext to manage my ISession object.

In previous projects I always managed that myself so whenever I needed a ISession object I would create it and store in HttpContext.Items collection. Pretty straightforward, but using a native solution (CurrentSessionContext) seems like a best option for this new project.

When I managed the object I was able to do a lazy initialization on it, meaning that I would only open a Session when I needed it and not in every request because I may not need it and would be wasting resource/time by opening it all the time.

Is there a simple way to do that with the CurrentSessionContext API?

Here is the code I'm using in the HttpModule responsible for this:


public class ContextualSessionModule : IHttpModule
{

    public void Init(HttpApplication context)
    {
        context.BeginRequest += context_BeginRequest;
        context.EndRequest += context_EndRequest;
    }

    public void Dispose()
    {
    }

    private static void context_BeginRequest(object sender, EventArgs e)
    {
        var application = (HttpApplication)sender;
        var context = application.Context;

        BindSession(context);
    }

    private static void BindSession(HttpContext context)
    {
        // Create a new session (it's the beginning of the request)
        var session = SessionBuilderFactory.CurrentSessionFactory.OpenSession();

        // Tell NH session context to use it
        CurrentSessionContext.Bind(session);
    }

    private static void context_EndRequest(object sender, EventArgs e)
    {
        var application = (HttpApplication)sender;
        var context = application.Context;

        UnbindSession(context);
    }

    private static void UnbindSession(HttpContext context)
    {
        // Get the default NH session factory
        var factory = SessionBuilderFactory.CurrentSessionFactory;

        // Give it to NH so it can pull the right session
        var session = CurrentSessionContext.Unbind(factory);

        if (session == null) return;
        session.Flush();
        session.Close();
    }
}

Edit

Diego pretty much nailed it, but I thought a little bit more about this and I remembered the main reason why I implemented that control myself: transactions.

I'm a Onion Architecture guy so my domain objects (who are the ones who know when to start a transaction) does not have access to infrastructure so they cannot start transactions.

In order to solve this, I use lazy initialization and always start a transaction when opening a Session. Committing happens when the request ends and no exceptions were caught. Besides this, there is Ayende's advice to always use transactions, even when querying. Any thoughts?


Solution

  • While not directly answering your question, I think: why?

    A session is a lightweight object. If you don't use it, it just initializes some internal structures, but it doesn't open a DB connection or anything.

    There are some examples around (just Google) to avoid opening sessions for static objects in order to save a little time/memory. Other than that, it might not be worth it, unless your profiling shows it's hurting your performance.

    Update: for transaction needs, have a look at the CpBT implementation in uNhAddIns.