将 SharpArchitecture 的 NHibernateSession 与不同的线程结合使用

发布于 2024-11-17 22:30:17 字数 2095 浏览 2 评论 0原文

我在 ASP.NET MVC 3 应用程序中使用 SharpArchitecture。一切都运转良好。

使用 SharpArchitecture 的 NHibernateInitializer 为每个请求初始化一个新会话,如下所示:

    protected void Application_BeginRequest(object sender, EventArgs e)
    {
        NHibernateInitializer.Instance().InitializeNHibernateOnce(InitializeNHibernateSession);
    }

    private void InitializeNHibernateSession(ISessionStorage sessionStorage)
    {
        NHibernateSession.ConfigurationCache = new NHibernateConfigurationFileCache(
            new[] { "App.Core" });
        NHibernateSession.Init(
            sessionStorage,
            new[] { Server.MapPath("~/bin/" + ApplicationSettings.Instance.NHibernateMappingAssembly) },
            new AutoPersistenceModelGenerator().Generate(),
            Server.MapPath("~/NHibernate.config"));

        NHibernateSession.AddConfiguration(ApplicationSettings.NHIBERNATE_OTHER_DB,
                                           new[] { Server.MapPath("~/bin/" + ApplicationSettings.Instance.NHibernateMappingAssembly) },
                                           new AutoPersistenceModelGenerator().Generate(),
                                           Server.MapPath("~/NHibernateForOtherDb.config"), null, null, null);
    }

正如您所看到的,我们还访问了多个数据库。一切都很好。

这是我遇到问题的地方。

我需要启动一个单独的线程来执行数据库轮询机制。我的意图是做这样的事情:

    protected void Application_Start()
    {
            ....
            ThreadingManager.Instance.ExecuteAction(() =>
            {
                // initialize another NHibernateSession within SharpArchitecture somehow
                NHibernateInitializer.Instance().InitializeNHibernateOnce(InitializeNHibernateSession);

                var service = container.Resolve<IDatabaseSynchronizationService>();
                service.SynchronizeRepositories();
            });
}

通过我的 SynchronizationService,一些存储库被调用。显然,当他们尝试访问会话时,会抛出异常,因为会话为空。

这是我的问题。我如何利用 SharpArchitecture 的 NHibernateSession 并以某种方式将它或它的副本在我的轮询线程中旋转?我希望这可以完成,而不必绕过使用 SharpArchitecture 使用的内置 SessionManagers 和 SessionFactories。

I'm using SharpArchitecture in an ASP.NET MVC 3 application. Everything works wonderfully.

Using SharpArchitecture's NHibernateInitializer to initialize a new Session per request like so:

    protected void Application_BeginRequest(object sender, EventArgs e)
    {
        NHibernateInitializer.Instance().InitializeNHibernateOnce(InitializeNHibernateSession);
    }

    private void InitializeNHibernateSession(ISessionStorage sessionStorage)
    {
        NHibernateSession.ConfigurationCache = new NHibernateConfigurationFileCache(
            new[] { "App.Core" });
        NHibernateSession.Init(
            sessionStorage,
            new[] { Server.MapPath("~/bin/" + ApplicationSettings.Instance.NHibernateMappingAssembly) },
            new AutoPersistenceModelGenerator().Generate(),
            Server.MapPath("~/NHibernate.config"));

        NHibernateSession.AddConfiguration(ApplicationSettings.NHIBERNATE_OTHER_DB,
                                           new[] { Server.MapPath("~/bin/" + ApplicationSettings.Instance.NHibernateMappingAssembly) },
                                           new AutoPersistenceModelGenerator().Generate(),
                                           Server.MapPath("~/NHibernateForOtherDb.config"), null, null, null);
    }

As you can see, we are also hitting multiple databases. All that's fine.

Here's where I run into an issue.

I need to spin up a separate thread to execute a database polling mechanism. My intention was to do something like this:

    protected void Application_Start()
    {
            ....
            ThreadingManager.Instance.ExecuteAction(() =>
            {
                // initialize another NHibernateSession within SharpArchitecture somehow
                NHibernateInitializer.Instance().InitializeNHibernateOnce(InitializeNHibernateSession);

                var service = container.Resolve<IDatabaseSynchronizationService>();
                service.SynchronizeRepositories();
            });
}

And through my SynchronizationService, some repositories get called. Obviously when they attempt to access their session, an exception is thrown because the Session is null.

Here's my question. How can I leverage SharpArchitecture's NHibernateSession and somehow have it or a copy of it, spun up inside my polling thread? I am hoping this can be done without having to bypass using the built in SessionManagers and SessionFactories used by SharpArchitecture.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

分分钟 2024-11-24 22:30:17

我假设 sessionStorage 是一个 SharpArch.Web.NHibernate.WebSessionStorage 对象,对吗?如果是这样,那么问题不在于 NHibernate Session 为 null,而可能是在您的线程上,HttpContext.Current 为 null,并且 WebSessionStorage 对象依赖 HttpContext.Current 来完成其工作(请参阅 这段代码,特别是第 37 行,当从线程调用时,上下文为 null,因此会发生 null 异常)。

我认为解决方案是编写一个不同的 SessionStorage 对象来检查 HttpContext.Current 是否为 null,如果是,则使用线程本地存储来存储 NHibernate Session(此解决方案来自于另一篇 StackOverflow 文章讨论了同样的事情:在Web应用程序Application_Start方法中初始化NServiceBus时出现NullReferenceException

编辑

也许是这样的:

public class HybridWebSessionStorage : ISessionStorage
{

    static ThreadLocal<SimpleSessionStorage> threadLocalSessionStorage;

    public HybridWebSessionStorage( HttpApplication app )
    {
        app.EndRequest += Application_EndRequest;
    }

    public ISession GetSessionForKey( string factoryKey )
    {
        SimpleSessionStorage storage = GetSimpleSessionStorage();
        return storage.GetSessionForKey( factoryKey );
    }

    public void SetSessionForKey( string factoryKey, ISession session )
    {
        SimpleSessionStorage storage = GetSimpleSessionStorage();
        storage.SetSessionForKey( factoryKey, session );
    }

    public System.Collections.Generic.IEnumerable<ISession> GetAllSessions()
    {
        SimpleSessionStorage storage = GetSimpleSessionStorage();
        return storage.GetAllSessions();
    }

    private SimpleSessionStorage GetSimpleSessionStorage()
    {
        HttpContext context = HttpContext.Current;
        SimpleSessionStorage storage;
        if ( context != null )
        {
            storage = context.Items[ HttpContextSessionStorageKey ] as SimpleSessionStorage;
            if ( storage == null )
            {
                storage = new SimpleSessionStorage();
                context.Items[ HttpContextSessionStorageKey ] = storage;
            }
        }
        else
        {
            if ( threadLocalSessionStorage == null )
                threadLocalSessionStorage = new ThreadLocal<SimpleSessionStorage>( () => new SimpleSessionStorage() );
            storage = threadLocalSessionStorage.Value;
        }
        return storage;
    }

    private static readonly string HttpContextSessionStorageKey = "HttpContextSessionStorageKey";

    private void Application_EndRequest( object sender, EventArgs e )
    {
        NHibernateSession.CloseAllSessions();

        HttpContext context = HttpContext.Current;
        context.Items.Remove( HttpContextSessionStorageKey );
    }
}

注意:当你完成你的操作时,你必须确保调用 NHibernateSession.CloseAllSessions()不过,请在线程上工作,因为当线程完成时,Application_EndRequest 不会被触发。

I assume that sessionStorage is a SharpArch.Web.NHibernate.WebSessionStorage object, right? If so then the issue isn't so much that the NHibernate Session is null, it's probably that on your thread, HttpContext.Current is null, and the WebSessionStorage object relies on HttpContext.Current to do its work (see this code, particularly line 37, where, when called from a thread, context is null, so a null exception occurs).

I think the solution would be to write a different SessionStorage object that checks to see if HttpContext.Current is null, and if it is, use thread local storage to store NHibernate Sessions in instead (this solution gleaned from this other StackOverflow article which talks about the same sort of thing: NullReferenceException when initializing NServiceBus within web application Application_Start method)

EDIT

Something like this perhaps:

public class HybridWebSessionStorage : ISessionStorage
{

    static ThreadLocal<SimpleSessionStorage> threadLocalSessionStorage;

    public HybridWebSessionStorage( HttpApplication app )
    {
        app.EndRequest += Application_EndRequest;
    }

    public ISession GetSessionForKey( string factoryKey )
    {
        SimpleSessionStorage storage = GetSimpleSessionStorage();
        return storage.GetSessionForKey( factoryKey );
    }

    public void SetSessionForKey( string factoryKey, ISession session )
    {
        SimpleSessionStorage storage = GetSimpleSessionStorage();
        storage.SetSessionForKey( factoryKey, session );
    }

    public System.Collections.Generic.IEnumerable<ISession> GetAllSessions()
    {
        SimpleSessionStorage storage = GetSimpleSessionStorage();
        return storage.GetAllSessions();
    }

    private SimpleSessionStorage GetSimpleSessionStorage()
    {
        HttpContext context = HttpContext.Current;
        SimpleSessionStorage storage;
        if ( context != null )
        {
            storage = context.Items[ HttpContextSessionStorageKey ] as SimpleSessionStorage;
            if ( storage == null )
            {
                storage = new SimpleSessionStorage();
                context.Items[ HttpContextSessionStorageKey ] = storage;
            }
        }
        else
        {
            if ( threadLocalSessionStorage == null )
                threadLocalSessionStorage = new ThreadLocal<SimpleSessionStorage>( () => new SimpleSessionStorage() );
            storage = threadLocalSessionStorage.Value;
        }
        return storage;
    }

    private static readonly string HttpContextSessionStorageKey = "HttpContextSessionStorageKey";

    private void Application_EndRequest( object sender, EventArgs e )
    {
        NHibernateSession.CloseAllSessions();

        HttpContext context = HttpContext.Current;
        context.Items.Remove( HttpContextSessionStorageKey );
    }
}

NOTE: You will have to make sure you call NHibernateSession.CloseAllSessions() when you have finished doing your work on the thread though, as Application_EndRequest won't get fired when your thread completes.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文