Web API 2 HTTP模块首先触发EndRequest事件?

时间:2014-07-28 01:51:27

标签: nhibernate asp.net-web-api httpmodule

我正在尝试实施与我最初在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先被调用?

LazySessionContextHTTPModule

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>

1 个答案:

答案 0 :(得分:0)

结果我只需要在HttpModules节点中注册system.webServer而不是system.Web