【问题标题】:HttpModule.Init - safely add HttpApplication.BeginRequest handler in IIS7 integrated modeHttpModule.Init - 在 IIS7 集成模式下安全地添加 HttpApplication.BeginRequest 处理程序
【发布时间】:2011-04-12 08:57:38
【问题描述】:

我的问题与以下类似但不完全相同:

Why can't my host (softsyshosting.com) support BeginRequest and EndRequest event handlers?(我还阅读了其中引用的 mvolo 博客)

我们的目标是使用通过 system.webServer 配置集成的普通 HttpModule 成功地将 HttpApplication.BeginRequest 挂接到 IHttpModule.Init 事件(或模块内部的任何位置)中,即没有:

  1. 入侵 Global.asax 或
  2. 覆盖 HttpApplication(该模块旨在自包含和可重用,例如,我有这样的配置):

    <system.webServer>
    <validation validateIntegratedModeConfiguration="false"/>
    <modules>
      <remove name="TheHttpModule" />
      <add name="TheHttpModule" type="Company.HttpModules.TheHttpModule" preCondition="managedHandler" /> 
    

到目前为止,我尝试将侦听器附加到 HttpApplication.BeginRequest 的任何策略都会导致以下两种情况之一,症状 1 是 BeginRequest 永远不会触发,或者症状 2 是在所有托管请求上引发以下异常,我无法从用户代码中捕获和处理它:

Stack Trace:
[NullReferenceException: Object reference not set to an instance of an object.]
System.Web.PipelineModuleStepContainer.GetEventCount(RequestNotification notification, Boolean isPostEvent) +30
System.Web.PipelineStepManager.ResumeSteps(Exception error) +1112
System.Web.HttpApplication.BeginProcessRequestNotification(HttpContext context, AsyncCallback cb) +113
System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context) +616

在 Init 中注释掉 app.BeginRequest += new EventHandler(this.OnBeginRequest) 当然会停止异常。 Init 根本不引用 Context 或 Request 对象。

我试过了:

  • 删除了所有对项目中任何位置的 HttpContext.Current 的引用(仍然是症状 1)
  • 已测试从我的 OnBeginRequest 方法主体中删除所有代码,以确保问题不是方法内部的问题(= 异常)
  • 嗅探堆栈跟踪并仅在 InitializeApplication 未启动堆栈时调用 app.BeginRequest+=...(= BeginRequest 未触发)
  • 仅在第二次通过 Init 时调用 app.BeginRequest+=(= BeginRequest 未触发)

有人知道一个好的方法吗?是否有一些在模块中挂钩 Application_Start 的间接策略(似乎不太可能)?另一个事件,a) 可以从模块的构造函数或 Init 方法中挂钩,并且 b) 随后是附加 BeginRequest 事件处理程序的安全位置?

非常感谢

【问题讨论】:

    标签: c# iis-7 httpmodule integrated-pipeline-mode


    【解决方案1】:

    您的 HttpModule 的 Init 方法将被单个 Web 应用程序调用多次(而 global.asax 中的 Application_Start 只会在每个 AppDomain 中调用一次)。

    Init 确实是连接 BeginRequest 的地方。

    我也遇到过这个错误,它是由多次挂钩 BeginRequest 事件引起的。我不确定这是否是 IIS 7 集成模式中的错误...

    当您执行 app.BeginRequest 时,您是使用 IHttpModule 的 Init 方法的 context 参数调用 context.BeginRequest 还是调用 HttpContext.Current.BeginRequest += ...?

    【讨论】:

    • void IHttpModule.Init(HttpApplication app),我打电话给app.BeginRequest += new EventHandler(this.OnApplication_BeginRequest)。然后我使用类级静态布尔值_initted 来防止多次添加处理程序。这就是为什么情况让我陷入这样一个循环的部分原因。
    • 这里有同样的问题。我还在 IIS 网站上发布了一个帖子,希望来自 Microsoft 的人能得到答案:forums.iis.net/p/1164977/1972908.aspx
    • 有什么解决办法吗?我可以将 httpModule 添加到任何 ASP.NET 应用程序。但是,在尝试将 IHttpModule 添加到 SharePoint 2013 网站(基于 .NET 4.0)时,我得到了完全相同的错误。一旦我附加到 BeginRequest 事件,问题就会出现。
    • @PaulSmith,我不确定我是否理解,您是否尝试在基于请求的 HttpModule 中附加应用程序范围的事件?如果您尝试附加应用程序范围的事件,那么 Global.asax.cs 中有一个 Application_start。 IHttpModule.Init 将在每个保活请求中调用一次
    【解决方案2】:

    我遇到了与上述相同的问题。我发现一个实际的解决方法是始终删除然后添加处理程序。因此:

        public override void Init()
        {
            base.Init();
    
            lock (_initialisationLockObject)
            {
                BeginRequest -= Global_BeginRequest;
                BeginRequest += Global_BeginRequest;
            }
        }
    

    我怀疑事件处理程序在多次调用 init 中的一次或多次后被清除。如果您只在第一次小心地尝试添加事件处理程序,则稍后调用 init 不会添加事件,因此根本不会调用处理程序。如果您不尝试任何巧妙的方法来限制添加事件的次数,那么您会看到获得多个附件。 通过首先尝试删除然后添加(在锁内以停止任何粗糙的竞争条件)似乎可以解决问题。

    这太可怕了,我们不应该这样做!

    希望有帮助

    【讨论】:

    • 就我而言,我只需要执行以下操作: System.Web.HttpContext.Current.ApplicationInstance.BeginRequest += ApplicationInstance_BeginRequest;但它会抛出一个空指针异常 += -= 的解决方法
    • 你不应该附加来自 httpModule 的全局事件,使用来自 Global.asax.cs 的 Application_xxx 或 Session_xxx 方法
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-04-13
    • 1970-01-01
    • 2013-01-20
    • 1970-01-01
    • 1970-01-01
    • 2012-09-30
    • 2010-09-05
    相关资源
    最近更新 更多