2011-05-02 78 views
5

對於Web應用程序來說,處理會話的好方法是使用設置<property name="current_session_context_class">managed_web</property>,在Begin/EndRequest上調用CurrentSessionContext.Bind/Unbind。然後我可以在存儲庫類中使用sessionFactory.GetCurrentSession()與後臺工作的Web應用程序的Nhibernate會話管理策略?

這適用於所有頁面請求。但我有後臺工作人員正在做東西,並使用相同的存儲庫類來做東西。這些不會在Web請求中運行,因此會話處理將不起作用。

有關如何解決這個問題的任何建議?

回答

14

我解決它通過創建我自己的會話上下文類:

public class HybridWebSessionContext : CurrentSessionContext 
{ 
    private const string _itemsKey = "HybridWebSessionContext"; 
    [ThreadStatic] private static ISession _threadSession; 

    // This constructor should be kept, otherwise NHibernate will fail to create an instance of this class. 
    public HybridWebSessionContext(ISessionFactoryImplementor factory) 
    { 
    } 

    protected override ISession Session 
    { 
     get 
     { 
      var currentContext = ReflectiveHttpContext.HttpContextCurrentGetter(); 
      if (currentContext != null) 
      { 
       var items = ReflectiveHttpContext.HttpContextItemsGetter(currentContext); 
       var session = items[_itemsKey] as ISession; 
       if (session != null) 
       { 
        return session; 
       } 
      } 

      return _threadSession; 
     } 
     set 
     { 
      var currentContext = ReflectiveHttpContext.HttpContextCurrentGetter(); 
      if (currentContext != null) 
      { 
       var items = ReflectiveHttpContext.HttpContextItemsGetter(currentContext); 
       items[_itemsKey] = value; 
       return; 
      } 

      _threadSession = value; 
     } 
    } 
} 
+6

如果你不想引用'HttpContext.Current',你可以使用'NHibernate.Context.ReflectiveHttpContext'來確定一個上下文是否可用。例如,在您不想在數據訪問項目中引用'System.Web'的情況下,這非常有用。 – Siewers 2011-07-06 17:43:04

+1

謝謝你,小費!我編輯了代碼來代替它! :) – Allrameest 2011-07-07 11:52:08

+1

非常感謝你!一直困惑了半天 - 我有一個WCF服務的WebForms項目,'CurrentSessionContext.Bind'拋出'NullReferenceException'。你的代碼對我來說是完美無缺的:D – 2014-02-20 06:58:42

0

在我的項目中,我圍繞CurrentSessionContext寫了一個小包裝類。
也許你可以擴展它來滿足你的需求。
我想你只需要調整的BindSessionToRequestGetCurrentSession實施:

public static class SessionManager 
    { 
     private static ISessionFactory _sessionFactory = null; 
     private static ISessionFactory SessionFactory 
     { 
      get 
      { 
       if (_sessionFactory == null) 
       { 
        //check whether we're in web context or win context, and create the session factory accordingly. 
        if (System.Web.HttpContext.Current != null) 
        { 
         if (_sessionFactory == null) 
         { 
          _sessionFactory = DAOBase.GetSessionFactory(); 
         } 
        } 
        else 
        { 
         _sessionFactory = DAOBase.GetSessionFactoryForWin(); 
        } 
       } 
       return _sessionFactory; 
      } 
     } 

     public static void BindSessionToRequest() 
     { 
      ISession session = SessionManager.SessionFactory.OpenSession(); 
      NHibernate.Context.CurrentSessionContext.Bind(session); 
     } 

     public static bool CurrentSessionExists() 
     { 
      return NHibernate.Context.CurrentSessionContext.HasBind(SessionFactory); 
     } 

     public static void UnbindSession() 
     { 
      ISession session = NHibernate.Context.CurrentSessionContext.Unbind(SessionManager.SessionFactory); 
      if (session != null && session.IsOpen) 
      { 
       session.Close(); 
      } 
     } 

     public static ISession GetCurrentSession() 
     { 
      return SessionFactory.GetCurrentSession(); 
     } 
    } 
2

,我找到了最簡單的此方案來處理自己使用DI庫和「混合」範圍內創建會話(在StructureMap,這被定義爲InstanceScope.Hybrid)。這將通過HttpContext在ASP.net應用程序域中的實例範圍和ThreadStatic在正常的應用程序域中實現,從而允許您在兩者中使用相同的方法。

我確定其他DI庫提供了類似的功能。

+0

這可能會工作。但是我使用的Castle並沒有那種混合式的生活方式。所以我必須自己建造它。然後構建一個NHibernate會話上下文類更簡單(請參閱我的答案)。但是謝謝你間接給我這個想法。 :) – Allrameest 2011-05-03 14:37:29

相關問題