针对后台工作者的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周围编写了一个小包装类。
也许您可以扩展它以满足您的需求。
我想你只需要调整BindSessionToRequest
和GetCurrentSession
的实现:
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(); } }