我正在尝试实施与我最初在NHibernate session management/repository pattern code found here上阅读的实施相关的NHibernate Forge page about effective session management。
我正在使用ASP.NET Web API 2,并且遇到HTTPModule事件的问题。当我使用简单的主页/索引操作运行应用时,我在System.Collections.Generic.KeyNotFoundException
方法中出现UnBind
错误。
当我调试时,BeginRequest
从未被调用,并且某种程度上EndRequest
正在崩溃。我相信这是错误的来源。
我错过了一些明显的东西吗?为什么EndRequest
先被调用?
LazySessionContext
和HTTPModule
:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using NHibernate;
using NHibernate.Context;
using NHibernate.Engine;
namespace MyService.Service.Infrastructure.SessionManagement
{
//Is up to you to:
//-set the currentsessioncontextclass in nhibernate as follows:
// configuration.Properties[Environment.CurrentSessionContextClass]
// = typeof (LazySessionContext).AssemblyQualifiedName;
//-implement ISessionFactoryProvider or use Castle Typed Factories:
// container.Register(Component.For<ISessionFactoryProvider>().AsFactory());
//-load the SessionFactoryProvider in the HttpApplication as follows:
// HttpContext.Current.Application[SessionFactoryProvider.Key]
// = your instance of ISessionFactoryProvider;
//-inject ISessionFactory in Daos and use GetCurrentSessionContext()
public class LazySessionContext : ICurrentSessionContext
{
private readonly ISessionFactoryImplementor factory;
private const string CurrentSessionContextKey = "NHibernateCurrentSession";
public LazySessionContext(ISessionFactoryImplementor factory)
{
this.factory = factory;
}
/// <summary>
/// Retrieve the current session for the session factory.
/// </summary>
/// <returns></returns>
public ISession CurrentSession()
{
Lazy<ISession> initializer;
var currentSessionFactoryMap = GetCurrentFactoryMap();
if (currentSessionFactoryMap == null ||
!currentSessionFactoryMap.TryGetValue(factory, out initializer))
{
return null;
}
return initializer.Value;
}
/// <summary>
/// Bind a new sessionInitializer to the context of the sessionFactory.
/// </summary>
/// <param name="sessionInitializer"></param>
/// <param name="sessionFactory"></param>
public static void Bind(Lazy<ISession> sessionInitializer, ISessionFactory sessionFactory)
{
var map = GetCurrentFactoryMap();
map[sessionFactory] = sessionInitializer;
}
/// <summary>
/// Unbind the current session of the session factory.
/// </summary>
/// <param name="sessionFactory"></param>
/// <returns></returns>
public static ISession UnBind(ISessionFactory sessionFactory)
{
var map = GetCurrentFactoryMap();
var sessionInitializer = map[sessionFactory];
map[sessionFactory] = null;
if (sessionInitializer == null || !sessionInitializer.IsValueCreated) return null;
return sessionInitializer.Value;
}
/// <summary>
/// Provides the CurrentMap of SessionFactories.
/// If there is no map create/store and return a new one.
/// </summary>
/// <returns></returns>
private static IDictionary<ISessionFactory, Lazy<ISession>> GetCurrentFactoryMap()
{
var currentFactoryMap = (IDictionary<ISessionFactory, Lazy<ISession>>)
HttpContext.Current.Items[CurrentSessionContextKey];
if (currentFactoryMap == null)
{
currentFactoryMap = new Dictionary<ISessionFactory, Lazy<ISession>>();
HttpContext.Current.Items[CurrentSessionContextKey] = currentFactoryMap;
}
return currentFactoryMap;
}
}
public interface ISessionFactoryProvider
{
IEnumerable<ISessionFactory> GetSessionFactories();
}
public class SessionFactoryProvider
{
public const string Key = "NHibernateSessionFactoryProvider";
}
public class NHibernateSessionModule : IHttpModule
{
private HttpApplication app;
public void Init(HttpApplication context)
{
app = context;
context.BeginRequest += ContextBeginRequest;
context.EndRequest += ContextEndRequest;
context.Error += ContextError;
}
private void ContextBeginRequest(object sender, EventArgs e)
{
var sfp = (ISessionFactoryProvider)app.Context.Application[SessionFactoryProvider.Key];
foreach (var sf in sfp.GetSessionFactories())
{
var localFactory = sf;
LazySessionContext.Bind(
new Lazy<ISession>(() => BeginSession(localFactory)),
sf);
}
}
private static ISession BeginSession(ISessionFactory sf)
{
var session = sf.OpenSession();
session.BeginTransaction();
return session;
}
private void ContextEndRequest(object sender, EventArgs e)
{
var sfp = (ISessionFactoryProvider)app.Context.Application[SessionFactoryProvider.Key];
var sessionsToEnd = sfp.GetSessionFactories()
.Select(LazySessionContext.UnBind)
.Where(session => session != null);
foreach (var session in sessionsToEnd)
{
EndSession(session);
}
}
private void ContextError(object sender, EventArgs e)
{
var sfp = (ISessionFactoryProvider)app.Context.Application[SessionFactoryProvider.Key];
var sessionstoAbort = sfp.GetSessionFactories()
.Select(LazySessionContext.UnBind)
.Where(session => session != null);
foreach (var session in sessionstoAbort)
{
EndSession(session, true);
}
}
private static void EndSession(ISession session, bool abort = false)
{
if (session.Transaction != null && session.Transaction.IsActive)
{
if (abort)
{
session.Transaction.Rollback();
}
else
{
session.Transaction.Commit();
}
}
session.Dispose();
}
public void Dispose()
{
app.BeginRequest -= ContextBeginRequest;
app.EndRequest -= ContextEndRequest;
app.Error -= ContextError;
}
}
}
注册Web.config
的 HttpModule
:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="webpages:Version" value="3.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
<httpModules>
<add name="PerRequestLifestyle" type="Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule, Castle.Windsor" />
<add name="SessionPerRequest" type="MyService.Service.Infrastructure.SessionManagement.NHibernateSessionModule, MyService.Service" />
</httpModules>
</system.web>
<system.webServer>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
<modules runAllManagedModulesForAllRequests="true">
<add name="PerRequestLifestyle" type="Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule, Castle.Windsor" />
<add name="SessionPerRequest" type="MyService.Service.Infrastructure.SessionManagement.NHibernateSessionModule, MyService.Service" />
</modules>
</system.webServer>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Web.Optimization" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="1.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-1.5.2.14234" newVersion="1.5.2.14234" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-5.1.0.0" newVersion="5.1.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
答案 0 :(得分:0)
结果我只需要在HttpModules
节点中注册system.webServer
而不是system.Web
。