3

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 を通じて、いくつかのリポジトリが呼び出されます。明らかに、セッションにアクセスしようとすると、Session が null であるため例外がスローされます。

これが私の質問です。SharpArchitecture の NHibernateSession を活用して、それまたはそのコピーをポーリング スレッド内でスピンアップするにはどうすればよいですか? SharpArchitecture で使用される組み込みの SessionManagers と SessionFactories を使用してバイパスすることなく、これを実行できることを願っています。

4

1 に答える 1

7

それsessionStorageSharpArch.Web.NHibernate.WebSessionStorageオブジェクトだと思いますよね?その場合、問題は NHibernate セッションが null であるほどではありません。おそらく、スレッド上で HttpContext.Current が null であり、WebSessionStorage オブジェクトが HttpContext.Current に依存して作業を行っている可能性があります (このコード、特に行を参照してください) 37 で、スレッドから呼び出された場合、context が null であるため、null 例外が発生します)。

解決策は、null かどうかを確認する別の SessionStorage オブジェクトを作成し、HttpContext.Currentそうであれば、代わりにスレッド ローカル ストレージを使用して NHibernate セッションを格納することだと思います (この解決策は、同じ種類について話しているこの他の 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 が起動されないため、スレッドでの作業が終了したら必ず呼び出す必要があります。

于 2011-07-06T10:22:50.450 に答える