我在ASP中使用SharpArchitecture。NET MVC 3应用程序。一切都很顺利。
使用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();
});
}
通过我的同步服务,一些存储库被调用。显然,当他们试图访问会话时,会抛出异常,因为会话为null。
这是我的问题。我如何利用SharpArchitecture的NHibernateSession,并以某种方式将其或其副本旋转到我的轮询线程中?我希望这可以在不必绕过SharpArchitecture使用的内置SessionManagers和SessionFactory的情况下完成。
我假设sessionStorage
是SharpArch.Web.NHibernate.WebSessionStorage
对象,对吗?如果是这样的话,那么问题不在于NHibernate会话为空,可能是在你的线程HttpContext上。Current为null,WebSessionStorage对象依赖于HttpContext。Current来完成它的工作(请参阅此代码,特别是第37行,当从线程调用时,上下文为null,因此会发生null异常(。
我认为解决方案是编写一个不同的SessionStorage对象,检查HttpContext.Current
是否为null,如果为null,使用线程本地存储将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不会被激发。