HttpModule.Init - safely add HttpApplication.BeginRequest handler in IIS7 integrated mode
Asked Answered
J

2

13

My question is similar but not identical to:

Why can't my host (softsyshosting.com) support BeginRequest and EndRequest event handlers? (I've also read the mvolo blog referenced therein)

The goal is to successfully hook HttpApplication.BeginRequest in the IHttpModule.Init event (or anywhere internal to the module), using a normal HttpModule integrated via the system.webServer config, i.e. one that doesn't:

  1. invade Global.asax or
  2. override the HttpApplication (the module is intended to be self-contained & reusable, so e.g. I have a config like this):

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

So far, any strategy I've tried to attach a listener to HttpApplication.BeginRequest results in one of two things, symptom 1 is that BeginRequest never fires, or symptom 2 is that the following exception gets thrown on all managed requests, and I cannot catch & handle it from user code:

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

Commenting out app.BeginRequest += new EventHandler(this.OnBeginRequest) in Init stops the exception of course. Init does not reference the Context or Request objects at all.

I have tried:

  • Removed all references to HttpContext.Current anywhere in the project (still symptom 1)
  • Tested removing all code from the body of my OnBeginRequest method, to ensure the problem wasn't internal to the method (= exception)
  • Sniffing the stack trace and only calling app.BeginRequest+=... when if the stack isn't started by InitializeApplication (= BeginRequest not firing)
  • Only calling app.BeginRequest+= on the second pass through Init (= BeginRequest not firing)

Anyone know of a good approach? Is there some indirect strategy for hooking Application_Start within the module (seems unlikely)? Another event which a) one can hook from a module's constructor or Init method, and b) which is subsequently a safe place to attach BeginRequest event handlers?

Thanks much

Jaredjarek answered 14/9, 2010 at 20:22 Comment(0)
A
3

Your HttpModule's Init method will get called multiple times by a single web application (whereas Application_Start in your global.asax will only get called once per AppDomain).

Init is indeed the place to hook onto BeginRequest.

I have encountered this error as well and it was caused by hooking onto the BeginRequest event more than once. I'm not sure if it is a bug in IIS 7 integrated mode or not...

When you do app.BeginRequest are you calling context.BeginRequest using the context parameter to your IHttpModule's Init method or are you calling HttpContext.Current.BeginRequest += ...?

Ate answered 14/9, 2010 at 20:34 Comment(4)
in void IHttpModule.Init(HttpApplication app), I call app.BeginRequest += new EventHandler(this.OnApplication_BeginRequest). Then I use a class-level static bool, _initted, to prevent adding the handler multiple times. That's partly why the situation is knocking me for such a loop.Jaredjarek
Same issue here. I also posted to a thread on the IIS site hoping someone from Microsoft might have an answer: forums.iis.net/p/1164977/1972908.aspxTimber
Any solution? I can add a httpModule to any ASP.NET application. However I get the exact same error when trying to add an IHttpModule to a SharePoint 2013 site (.NET 4.0 based). The problem occurs as soon as I attach to the BeginRequest event.Nestor
@PaulSmith, I'm not sure if I understand, are you trying to attach an application wide event inside a HttpModule that is request based? if you are trying to attach an application wide event, then there is an Application_start in Global.asax.cs. IHttpModule.Init will be called once per keep-alive requestBarracuda
D
1

I had the same problems described above. I found that a practical work around was to always remove then add the handler. thus:

    public override void Init()
    {
        base.Init();

        lock (_initialisationLockObject)
        {
            BeginRequest -= Global_BeginRequest;
            BeginRequest += Global_BeginRequest;
        }
    }

I suspect that the event handlers are getting cleared down after one or more of the multiple calls to the init. If you carefully only try and add the event handler the first time, the later times init gets called don't get a event added and hence the handler doesn't get called at all. If you don't try anything cunning to limit the number of times the event gets added, then you seen to get multiple attachments. By first trying to remove then add (inside a lock to stop any gnarly race conditions) seems to do the trick.

It is horrible though, and we shouldn't have to do this!

Hope that helps

Dirt answered 6/2, 2015 at 9:29 Comment(2)
In my case I just need to do something like: System.Web.HttpContext.Current.ApplicationInstance.BeginRequest += ApplicationInstance_BeginRequest; but it throws a null pointer exception The workaoround of += -= workedIatrogenic
You shouldn't be attaching global events from httpModule, use Application_xxx or Session_xxx methods from Global.asax.csBarracuda

© 2022 - 2024 — McMap. All rights reserved.