3

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

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

    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,调用了一些存储库。显然,当他们尝试访问他们的会话时,会抛出异常,因为 Session 为空。

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

4

1 回答 1

7

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

我认为解决方案是编写一个不同的 SessionStorage 对象来检查是否HttpContext.Current为空,如果是,则使用线程本地存储来存储 NHibernate Sessions事物:在 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 在线程完成时不会被触发。

于 2011-07-06T10:22:50.450 回答