具有后台工作人员的 Web 应用程序的休眠会话管理策略?

Posted

技术标签:

【中文标题】具有后台工作人员的 Web 应用程序的休眠会话管理策略?【英文标题】:Nhibernate session management strategy for web application with background-workers? 【发布时间】:2011-08-16 18:57:02 【问题描述】:

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

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

对如何解决这个问题有什么建议吗?

【问题讨论】:

【参考方案1】:

我通过创建自己的会话上下文类解决了这个问题:

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;
        
    

【讨论】:

如果不想引用HttpContext.Current,可以使用NHibernate.Context.ReflectiveHttpContext来判断上下文是否可用。这在您不想在数据访问项目中引用 System.Web 的情况下很有用。 非常感谢!对此困惑了半天——我有一个带有 WCF 服务的 WebForms 项目,而CurrentSessionContext.Bind 正在抛出一个NullReferenceException。你的代码对我来说完美无缺:D @Allrameest 另外在这个实现中你如何处理 ISession 的翻译? 这就是解决方案!非常感谢:)【参考方案2】:

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

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

【讨论】:

这可能会奏效。但我使用的 Castle 没有那种开箱即用的混合生活方式。所以我必须自己建造它。然后构建一个 NHibernate 会话上下文类就更简单了(见我的回答)。但是感谢您间接地给了我这个想法。 :)【参考方案3】:

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

【讨论】:

以上是关于具有后台工作人员的 Web 应用程序的休眠会话管理策略?的主要内容,如果未能解决你的问题,请参考以下文章

管理休眠会话的策略

具有二进制 UUID/二进制参数的休眠会话过滤器失败

CVE-2021-40904——CheckMk后台RCE

CVE-2021-40904——CheckMk后台RCE

如何使用 Spring 管理具有不同 jdbc(或休眠?)的多个“运行时注意到”数据库连接?

从应用程序获取休眠会话计数