Rick Strahl's Web Log

Wind, waves, code and everything in between...
ASP.NET • C# • HTML5 • JavaScript • AngularJs
Contact   •   Articles   •   Products   •   Support   •   Search
Ad-free experience sponsored by:
ASPOSE - the market leader of .NET and Java APIs for file formats – natively work with DOCX, XLSX, PPT, PDF, images and more

Caveats with the runAllManagedModulesForAllRequests in IIS 7/8


One of the nice enhancements in IIS 7 (and now 8) is the ability to be able to intercept non-managed - ie. non ASP.NET served - requests from within ASP.NET managed modules. This opened up a ton of new functionality that could be applied across non-managed content using .NET code.

I thought I had a pretty good handle on how IIS 7's Integrated mode pipeline works. But when I put together some samples last night I realized that the way that managed and unmanaged requests fire into the pipeline is downright confusing especially when it comes to the runAllManagedModulesForAllRequests attribute. There are a number of settings that can affect whether a managed module receives non-ASP.NET content requests such as static files or requests from other frameworks like PHP or ASP classic.

Native and Managed Modules

The integrated mode IIS pipeline for IIS 7 and later - as the name suggests - allows for integration of ASP.NET pipeline events in the IIS request pipeline. Natively IIS runs unmanaged code and there are a host of native mode modules that handle the core behavior of IIS. All the default modules that IIS installs with are unmanaged ones. If you set up a new IIS site or application without managed code support only the native modules are supported and fired without any interaction between native and managed code.

If you use the Integrated pipeline with managed code enabled however things get a little more confusing as there both native modules and .NET managed modules can fire against the same IIS request.

If you open up the IIS Modules dialog you see both managed and unmanaged modules. Unmanaged modules point at physical files on disk, while managed modules point at .NET types and files referenced from the GAC or the current project's BIN folder.

IISModulesInConsole

Both native and managed modules can co-exist and execute side by side and on the same request. When running in IIS 7 the IIS pipeline actually instantiates a the ASP.NET  runtime (via the System.Web.PipelineRuntime class) which unlike the core HttpRuntime classes in ASP.NET receives notification callbacks when IIS integrated mode events fire. The IIS pipeline is smart enough to detect whether managed handlers are attached and if there are none these notifications don't fire, improving performance.

The good news about all of this for .NET devs is that ASP.NET style modules can be used for just about every kind of IIS request. All you need to do is create a new Web Application and enable ASP.NET on it, and then attach managed handlers. Handlers can look at ASP.NET content (ie. ASPX pages, MVC, WebAPI etc. requests) as well as non-ASP.NET content including static content like HTML files, images, javascript and css resources etc. It's very cool that this capability has been surfaced.

However, with that functionality comes a lot of responsibility. Because every request passes through the ASP.NET pipeline, if managed modules (or handlers) are attached there are possible performance implications that come with it. Running through the ASP.NET pipeline does add some overhead.

ASP.NET and Your Own Modules

When you create a new ASP.NET project typically the Visual Studio templates create the modules section like this:

  <system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    <modules runAllManagedModulesForAllRequests="true" >
    </modules>  </system.webServer> 

Specifically the interesting thing about this is the runAllManagedModulesForAllRequest="true" flag. It would seem that it determines whether any registered managed modules always run. If you assume that though, you'd only be partially right :-). Realistically this flag does not control whether managed code is fired for all requests or not. Rather it is an override for the preCondition="managedHandler" flag on a particular module registration.

The preCondition="managedHandler" attribute on an HttpModule mean "Only handle ASP.NET pipeline events - no native pipeline events". The runAllManagedModulesForAllRequests flag essentially manipulates the preCondition attribute to perform its actions.

runAllManagedModulesForAllRequests="true" - works as you'd expect

With the flag set to true all requests - native and managed - fire through your ASP.NET modules. This flag essentially overrides the preCondition="managedHandler" and removes the managed handler flag, and thus forces all requests through your module (and any other managed module).

In other words, your module will have to handle all requests. So far so obvious -  it does as the name suggests.

runAllManagedModulesForAllRequests="false" - different than you might think!

When the value is false though, the behavior is a little bit unexpected. You probably expect that native, non-ASP.NET requests no longer get funneled through the ASP.NET Module pipeline. But that's only partially true. A value of true is not the opposite of what the true behavior does.

When the value is false the default settings for preCondition="" are used on the module. Which means that if you have a preCondition="managedHandler" it only fires managed requests. If it doesn't have a preCondition="managedHandler" then all requests - native and managed - are fired against your module.

For example, if I create a module like this:

<add name="SharewareModule" type="HowAspNetWorks.SharewareMessageModule"  />

it will still fire against ALL requests regardless of the runAllManagedModulesForAllRequests flag. Even if the value runAllManagedModulesForAllRequests="false", the module is fired with unmanaged requests going through it. Not quite as expected.

So the only way to really prevent the managed module from firing native requests is by explicitly providing preCondition="managedHandler":

<add name="SharewareModule" type="HowAspNetWorks.SharewareMessageModule" 
preCondition="managedHandler" />

and then set runAllManagedModulesForAllRequests="false" my module only fires against managed requests. If I switch the flag to true, now my module ends up handling all IIS requests that are passed through from IIS.

The moral of the story here is that if you intend to only look at ASP.NET content, you should always set the preCondition="managedHandler" attribute to ensure that only managed requests are fired on this module. But even if you do this, realize that runAllManagedModulesForAllRequests="true" can override this setting, so your module still can fire on native requests and has to anticipate handling any kind of request.

Posted in IIS7   ASP.NET  

The Voices of Reason


 

Lelala
October 26, 2012

# re: Caveats with the runAllManagedModulesForAllRequests in IIS 7/8

AH, ok - now i understand the problem i had with my own modules and the requests going through it when it comes to requests to "WebResource.axd"/scripts and other static content, e.g. the image-folder in the webapp root folder.
I hadn't to care about this until i switched to next version of our ORM, for which i had to develop a custom HTTP module to get the stuff working.

John K
November 29, 2012

# re: Caveats with the runAllManagedModulesForAllRequests in IIS 7/8

I think in the statement "Unmanaged modules point at physical files on disk, while unmanaged modules point at .NET types" the second "unmanaged" should be "managed".

Vladimir
April 14, 2013

# re: Caveats with the runAllManagedModulesForAllRequests in IIS 7/8

Hi great article. I have been looking into possibility to deffer my handlers on Post map handler event and i see that for static resources in handler and currentHandler is null. Does this mean that non manged (native) handlers are not visible in asp.net. Is this good way to deffer managed from not manged handlers? Cause i would like to add some logic, but not if it is a static resource.

Rick Strahl
April 14, 2013

# re: Caveats with the runAllManagedModulesForAllRequests in IIS 7/8

@Vladimir - you can only see managed handlers and modules. Nothing unmanaged shows up in the pipeline.

Vladimir
April 15, 2013

# re: Caveats with the runAllManagedModulesForAllRequests in IIS 7/8

Yep, that is what i was thinking. If I set it runAllManagedModulesForAllRequests to false, event's like PostMapRequestHandler want even trigger for static resources. So that is one option also. Thank you!

William Gross
August 14, 2014

# re: Caveats with the runAllManagedModulesForAllRequests in IIS 7/8

Thank you so much for this post, Rick! Your post in combination with http://blogs.msdn.com/b/tmarq/archive/2010/05/26/how-extensionless-urls-are-handled-by-asp-net-v4.aspx was the only documentation I could find on the *true* purpose of ExtensionlessUrlHandler, which is to force all extensionless requests to run in managed mode so that they have the opportunity to be routed by MVC or Web API.

Agustin
July 07, 2015

# re: Caveats with the runAllManagedModulesForAllRequests in IIS 7/8

Hey there Rick.
I had this issue, a custom HttpApplication, defined in global.asax, was not firing its events for non-managed requests.
Toggling runAllManagedModulesForAllRequests=true was doing the trick. But I was not able to find a freaking reason or explanation as to why it was like that.
Until I found this article. It gave me closure !
Thanks :)
 

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2017