2011-05-02 61 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

相关问题