针对后台工作者的Web应用程序的Nhibernate会话管理策略?

对于Web应用程序,处理会话的好方法似乎是使用设置managed_web ,在Begin / EndRequest上调用CurrentSessionContext.Bind/Unbind 。 然后我可以在存储库类中使用sessionFactory.GetCurrentSession()

这适用于所有页面请求。 但是我有后台工作人员做东西并使用相同的存储库类来做事情。 这些不在Web请求中运行,因此会话处理将不起作用。

有关如何解决这个问题的任何建议?

我通过创建自己的会话上下文类来解决它:

 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; } } } 

我发现在这种情况下最简单的方法是使用DI库和“混合”范围自己处理会话创建(在StructureMap中,这被定义为InstanceScope.Hybrid)。 这将通过ASP.net应用程序域中的HttpContext和普通应用程序域中的ThreadStatic来实例化范例,允许您在两者中使用相同的方法。

我相信其他DI库提供了类似的function。

在我的项目中,我在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(); } }