views:

66

answers:

2

I'm writing a web app using ASP.NET MVC 2 and picked NHibernate as my ORM. I basically learned my basics from watching the Summer of NHibernate series, and have adopted the authors session per request strategy for managing a session (Ep 13). Things seem to work well, but I'm concerned about whether this is a functional real world approach to managing a session and being thread safe. If not then I'm open to other examples.

I've added code to elaborate. Here is my code that sets up the SessionFactory:

public class NHibernateSessionManager
{
    public static readonly ISessionFactory SessionFactory;

    static NHibernateSessionManager()
    {
        try
        {
            Configuration cfg = new Configuration();

            if (SessionFactory != null)
                throw new Exception("trying to init SessionFactory twice!");

            SessionFactory = cfg.Configure().BuildSessionFactory();
        }
        catch (Exception ex)
        {
            Console.Error.WriteLine(ex);
            throw new Exception("NHibernate initialization failed", ex);
        }
    }
    public static ISession OpenSession()
    {
        return SessionFactory.OpenSession();
    }
}

And this is where I have the web request start and stop the transaction:

public class NHibernateSessionPerRequestModule : IHttpModule
{
    public void Dispose()
    {
    }

    public void Init(HttpApplication context)
    {
        context.BeginRequest +=new EventHandler(Application_BeginRequest);
        context.EndRequest +=new EventHandler(Application_EndRequest);
    }

    private void Application_BeginRequest(object sender, EventArgs e)
    {
        ISession session = NHibernateSessionManager.OpenSession();
        session.BeginTransaction();
        CurrentSessionContext.Bind(session);
    }
    private void Application_EndRequest(object sender, EventArgs e)
    {
        ISession session = CurrentSessionContext.Unbind(NHibernateSessionManager.SessionFactory);
        if(session != null)
            try
            {
                session.Transaction.Commit();
            }
            catch (Exception)
            {
                session.Transaction.Rollback();
            }
            finally
            {
                session.Close();
            }
    }
}

And this is how I would grab a session from the session factory for one of my repositories in a Controller class:

CompanyRepository _companyRepository = new CompanyRepository(NHibernateSessionManager.SessionFactory.GetCurrentSession());
A: 

I was curious so I googled around.

HttpContext.Items can be used by multiple threads.

Nhibernate Sessions are not thread safe.

And then there is there answer: ( possible dupe ) http://stackoverflow.com/questions/629719/nhibernate-thread-safety-with-session

So it seems this recipe for disaster can be managed effectively. Because you didn't post the code that Summer of Nhibernate uses its hard to say whether your implementation won't fall over.

jfar
So with the code above, because the ISession is static, its not thread safe?
mattnss
@mattnss - Read the answer I linked too. Looks like if your storing the session and not the factory itself you can get into trouble.
jfar
So in my code ive posted, i'm only storing the SessionFactory in a static variable, so it should be thread safe?
mattnss
You should read up on what the static keyword does, teach a man to fish and everything. Needless to say that is probably the worst thing you can do if you want sessions to be unique to each controller and httprequest.
jfar
I wholeheartedly agree about the teach a man to fish aspect. I ask the question because a lot of people seem to reference the Summer of NHibernate webcasts to NHibernate newbies and it would be good to know if learning it that way would be good for just theory or if it can be taken as a practical example towards the end of his sessions (I know in the beginning of his screencasts he does mention the initially introduced method to retrieve the session is not how you would execute it in the real world).
mattnss
@mattnss - I was just pointing out I can't write the entire solution for you.
jfar
Sure, I understand what you are saying and I wasn't hoping for someone to do the work for me. I was just hoping it would lead to some guidance as to whether Summer of NHibernate is a good session management strategy and hopefully why or why not. Thanks for your feedback.
mattnss
A: 

Taking a page from jfar I think I finally taught myself to fish (or maybe cast my pole in the right direction) on the subject and found some good articles that shed some light to elaborate on how the Summer of NHibernate scheme works. Googling around to find more details on NHibernate and Contextual Sessions helped me get a better grasp of the topic. I'm still new to NHibernate (and web programming in general) so please bear with me if this question and answer seem elementary.

It seems the Summer of NHibernate scheme is thread safe. My explanation will reference names from my code sample above. The SessionFactory variable is static, so its accessible from every thread, it is however a thread safe object (whereas as mentioned the ISession is not thread safe). The NHibernateSessionPerRequestModule establishes two events that will fire on a web request (Application_BeginRequest) and at the end of one (Application_EndRequest). Application_BeginRequest will grab an ISession object from which you can then bind it to the current context. That helps ensure that the ISession object is used for the duration of the web request and only for that thread. After a web request begins, an ISession is then retrievable with the .GetCurrentSession() for use with the _companyRepository. The Application_BeginRequest will also begin the transaction for you. The Application_EndRequest will unbind the ISession object, commit all changes at the end of your web request, and close the ISession.

Peter Wigle has an article which shows a similar example of how to implement session management: http://pwigle.wordpress.com/2008/11/21/nhibernate-session-handling-in-aspnet-the-easy-way

In that article the Global.asax is used to specify events for binding and unbinding instead of creating an IHttpModule.

Ayende has a nice clean example that uses the HttpContext to manage your ISessions: "http://ayende.com/Blog/archive/2009/08/05/do-you-need-a-framework.aspx" (Sorry I can only post 1 hyperlink due to my lack of pointage)

If I am way off base and or am not understanding something please feel free to interject, but as far as I can tell so long as a different ISession is being binded to each threads context it will be thread safe (unless there is a need to have a cross threaded ISession).

mattnss