title: NHibernate session management
body: <p>I use NHiberante at my win service. Sometimes I get</p>
  
  <pre><code>System.ObjectDisposedException: Session is closed!
  Object name: 'ISession'.
     at NHibernate.Impl.AbstractSessionImpl.ErrorIfClosed()
     at NHibernate.Impl.AbstractSessionImpl.CheckAndUpdateSessionStatus()
     at NHibernate.Impl.SessionImpl.FireSave(SaveOrUpdateEvent event)
     at NHibernate.Impl.SessionImpl.Save(Object obj)
     at Attraction.DAL.Repositories.Repository`1.Save(T entity)
     at Attraction.VideoDispatcher.Program.ThreadPoolCallback(Object threadContext)
  </code></pre>
  
  <p>I have no idea what's wrong.
  My session management subsystem:</p>
  
  <p>Repository:</p>
  
  <pre><code> public class Repository&lt;T&gt; : IRepository&lt;T&gt;, IDisposable
      {
          protected readonly bool CommitAtDispose;
          public Repository(bool commitAtDispose)
          {
              CommitAtDispose = commitAtDispose;
              StartSession();
          }
          private void StartSession()
          {
              if (NHibernateSession == null)
                  NHibernateHelper.StartSession();
          }
          public void Dispose()
          {
              if (CommitAtDispose)
                  Flush();
          }
          public void Flush()
          {
              NHibernateHelper.EndSession();
          }
          protected override sealed ISession NHibernateSession
          {
              get
              {
                  return SessionManager.CurrentSession; 
              }
          }       
          public virtual T GetById(int id)       
          public virtual List&lt;T&gt; GetAll()        
          public virtual List&lt;T&gt; GetByPage(int pageIndex, int pageSize)       
          public virtual int GetCount()        
          public virtual List&lt;T&gt; GetByCriteria(params ICriterion[] criterion)       
          public virtual T Save(T entity)       
          public virtual T Update(T entity)        
          public virtual void Delete(T entity)        
      }
  }
  </code></pre>
  
  <p>SessionManager - singletone for provide access to sessionfactory</p>
  
  <pre><code>public class SessionManager : ISessionFactoryProvider
  {
          private static readonly ILog Log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
          private readonly ISessionFactory sessionFactory;
          public static ISessionFactory SessionFactory
          {
              get { return Instance.sessionFactory; }
          }
          public ISessionFactory GetSessionFactory()
          {
              return sessionFactory;
          }
          public static ISession OpenSession()
          {
              return Instance.GetSessionFactory().OpenSession();
          }
          public static ISession CurrentSession
          {
              get
              {
                  if (!CurrentSessionContext.HasBind(Instance.GetSessionFactory()))
                      return null;
                  return Instance.GetSessionFactory().GetCurrentSession();
              }
          }
  
  
          public static SessionManager Instance
          {
              get
              {
                  return NestedSessionManager.sessionManager;
              }
          }
          private SessionManager()
          {
              Log.Info("Start creating factory");
              Configuration configuration = new Configuration().Configure();
              sessionFactory = configuration.BuildSessionFactory();
              Log.Info("End creating factory");
  
          }
  
          class NestedSessionManager
          {
              internal static readonly SessionManager sessionManager =
                  new SessionManager();
          }
      }
  </code></pre>
  
  <p>NhibernateHelper, which do some work for start and end session:</p>
  
  <pre><code>public static class NHibernateHelper
      {
          public static void StartSession()
          {
              var session = SessionManager.SessionFactory.OpenSession();
              session.BeginTransaction();
              CurrentSessionContext.Bind(session);
  
          }
          public static void EndSession()
          {
              var session = SessionManager.CurrentSession;
              CurrentSessionContext.Unbind(SessionManager.SessionFactory);
              if (session != null)
              {
                  try
                  {
                      if (session.Transaction != null &amp;&amp; session.Transaction.IsActive)
                          session.Transaction.Commit();
                  }
                  catch (Exception ex)
                  {
                      session.Transaction.Rollback();
                      throw new ApplicationException("Error committing database transaction. "+ex.Message, ex);
                  }
                  finally
                  {
                      session.Close();
                      session.Dispose();
  
                  }
              }
  
  
          }
      }
  </code></pre>
  
  <p>May be my design isn't so good, but I couldn't imagine how can I catch this error.</p>
  
  <p><strong>UPD</strong></p>
  
  <p>Sorry my config. I haven't migrate to fluent yet so:</p>
  
  <pre><code>&lt;hibernate-configuration xmlns="urn:nhibernate-configuration-2.2"&gt;
      &lt;session-factory&gt;
        &lt;property name="connection.provider"&gt;NHibernate.Connection.DriverConnectionProvider&lt;/property&gt;
        &lt;property name="dialect"&gt;NHibernate.Dialect.MySQLDialect&lt;/property&gt;
        &lt;property name="connection.driver_class"&gt;NHibernate.Driver.MySqlDataDriver&lt;/property&gt;
        &lt;property name="connection.connection_string"&gt;***&lt;/property&gt;
        &lt;property name="show_sql"&gt;false&lt;/property&gt;
        &lt;property name="default_schema"&gt;**_***&lt;/property&gt;
        &lt;property name="current_session_context_class"&gt;thread_static&lt;/property&gt;
        &lt;mapping assembly="***.Core"/&gt;
      &lt;/session-factory&gt;
    &lt;/hibernate-configuration&gt;
  </code></pre>
  
  <p><strong>UPD2</strong></p>
  
  <p>Save method:</p>
  
  <pre><code>        public virtual T Save(T entity)
          {
              NHibernateSession.Save(entity);
              return entity;
          }
  </code></pre>
  
  <p>Threadpool callback:</p>
  
  <pre><code>        public static void DetectStart(Object threadContext)
          {
              try
              {
                  var task = (TasksPerAttraction)threadContext;                
                  var startInfo = new ProcessStartInfo(..., ...)
                  {
                      UseShellExecute = false,
                      RedirectStandardOutput = true
                  };
                  Process p = Process.Start(startInfo);
                  var outputXml = p.StandardOutput.ReadToEnd();
                  p.WaitForExit();
                  var doc = XDocument.Parse(outputXml);
                  foreach (var xElement in doc.Root.Descendants("start"))
                  {
                      var startDetection = new StartDetection
                                               {
                                                   DtStart = DateTime.Parse(xElement.Attribute("startTime").Value),
                                                   Attraction = task.Attraction,                                                
                                               };
                      lock (spinLock)
                      {
                          using (var repo = new Repository&lt;StartDetection&gt;(true))
                              repo.Save(startDetection);
                      }
                  }
                  var tskRepo = new Repository&lt;Task&gt;(true);
                  foreach(var tsk in task.Tasks)
                  {
                      tsk.IsProcessedStart = true;
                      tskRepo.Update(tsk);
                  }
                  tskRepo.Flush();
              }
              catch (Exception ex)
              {
                  //....
              }
          }
  </code></pre>