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

时间:2011-05-02 06:48:14

标签: c# .net nhibernate sessionfactory

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

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

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

3 个答案:

答案 0 :(得分:15)

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

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

答案 1 :(得分:2)

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

我确信其他DI库提供了类似的功能。

答案 2 :(得分: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();
        }
    }