+1  A: 

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.

HTH,
Kent

Kent Boogaart
Thanks for the tip, unfortunately the same thing is shown. `SessionProvider.Dispose` is calling `SessionImpl.Dispose` is calling `SessionImpl.Close` ***after*** the exception is thrown.
Sekhat
Which means, nothing during "execution time" is explicitly closing it, which means something fishy is going on...
Sekhat
+3  A: 

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();
            }
        }
    }        
Jamie Ide
well that solved the problem thanks :) Do you have a full explanation what was causing the problem? I assume with you mention of ASP.NET being multi-threaded (which I knew) was something to do with it? Normally can you not use the same session across threads then?
Sekhat
I ran into exactly the same problem when I started with session-per-request. Using NHibernate Profiler, I could see that sessions were opened for requests for linked resources, such as CSS and JavaScript files, as well as the web page. Occasionally one of these requests will trigger the EndRequest and cause the session to close while another thread in the same request has a reference to it (race condition).
Jamie Ide
What calls EndContextSession()?
Ronnie Overby
I call it in Global.asax Application_EndRequest. You could also use an HttpHandler.
Jamie Ide