NHibernate, and odd "Session is Closed!" errors NHibernate, and odd "Session is Closed!" errors asp.net asp.net

NHibernate, and odd "Session is Closed!" errors


ASP.NET is multi-threaded so access to the ISession must be thread safe. Assuming you're using session-per-request, the easiest way to do that is to use NHibernate's built-in handling of contextual sessions.

First configure NHibernate to use the web session context class:

sessionFactory = Fluently.Configure()    .Database(        MsSqlConfiguration.MsSql2005.ConnectionString(p =>            p.FromConnectionStringWithKey("QoiSqlConnection")))    .Mappings(m => m.FluentMappings.AddFromAssemblyOf<JobMapping>())    .ExposeConfiguration(x => x.SetProperty("current_session_context_class", "web")    .BuildSessionFactory();

Then use the ISessionFactory.GetCurrentSession() to get an existing session, or bind a new session to the factory if none exists. Below I'm going to cut+paste my code for opening and closing a session.

    public ISession GetContextSession()    {        var factory = GetFactory(); // GetFactory returns an ISessionFactory in my helper class        ISession session;        if (CurrentSessionContext.HasBind(factory))        {            session = factory.GetCurrentSession();        }        else        {            session = factory.OpenSession();            CurrentSessionContext.Bind(session);        }        return session;    }    public void EndContextSession()    {        var factory = GetFactory();        var session = CurrentSessionContext.Unbind(factory);        if (session != null && session.IsOpen)        {            try            {                if (session.Transaction != null && session.Transaction.IsActive)                {                    session.Transaction.Rollback();                    throw new Exception("Rolling back uncommited NHibernate transaction.");                }                session.Flush();            }            catch (Exception ex)            {                log.Error("SessionKey.EndContextSession", ex);                throw;            }            finally            {                session.Close();                session.Dispose();            }        }    }        


I ran into Session Closed/ObjectDisposedExceptions intermittently when running integration tests for a Web API project I was working on.

None of the tips here solved it, so I built a debug version of NHibernate to find out more, and I saw it doing a linq query when the controller's Get function was returning with the IEnumerable of response objects.

It turned out that our repository was doing a linq query and returning the IEnumerable of the domain objects, but never calling ToList() to force the evaluation of the query. The service in turn returned the IEnumerable, and the Controller wrapped the enumerable with response objects and returned it.

During that return, the linq query finally got executed, but the NHibernate session got closed in the interim at some point, so it threw an exception. The solution was to always make sure we call .ToList() in the repository within the using session block before we return to the service.


I suggest you set a breakpoint on SessionImpl.Close / SessionImpl.Dispose and see who is calling it via the stack trace. You could also just build a debug version of NH for yourself and do the same.