Use a Single Web.config for IIS6 and IIS7

This is a re-post from something I wrote way back in 2008. Turns out that I still get several hits a day for the technical contents of this post, mostly from StackOverflow, so I’m putting this one back online to help people out (nothing more frustrating than finding an answer to your problem only to end up at a dead link). I’ve tweaked it slightly to bring it it current, but otherwise it’s as it was.

Begin wayback machine…

Original post date: April 8, 2008

The primary issue with running an ASP.NET site in IIS7 Integrated Pipeline mode is if you have any HTTP modules configured. See, the “problem” is that with ASP.NET under IIS6, there were essentially two pipelines: one for ASP.NET and one for IIS. A request would come into IIS and if the file extension was mapped to the ASP.NET ISAPI extension, the request would be passed off to aspnet_isapi.dll and was then processed by the ASP.NET pipeline, which is where the HTTP modules come into play with regards to events that occur in the pipeline. However, in IIS7 there is only one pipeline for those events, and it’s used for both IIS7 native modules and ASP.NET modules (once the pipeline events have been taken care of, the file is taken care of by the appropriate ISAPI extension).

Therefore, if your ASP.NET app has HTTP modules and you want to make sure it runs in both IIS6 and IIS7 Integrated Pipeline mode (from here on out just referred to as IIS7), you need to make some changes to web.config (there are other things to consider as well when running an ASP.NET site under IIS7, so definitely check out this article first for details).

The web.config changes needed are for your HTTP modules and handlers. For IIS6, they were configured in the <system.web> section, as such:

However, to get these to work in IIS7 you must *move them* from the <system.web> section to the new <system.webServer> section, which is what IIS7 requires when running in Integrated Pipeline mode (it’s not needed for Classic Pipeline mode). So instead of the above you’ll have this:

Notice there are a couple slight changes, which means you can’t just copy and paste these as-is from <system.web> into <system.webServer>:

  • <httpModules> and <httpHandlers> have been renamed to <modules> and <handlers>, respectively.
  • Each handler in IIS7 requires a name attribute. If you don’t specify it, you’ll get an error message.
  • The handlers node has an optional, but good-to-define accessPolicy attribute. This value depends on your handlers, so use the ones that are right for you.

Knowing this, to run your ASP.NET app on IIS6 and IIS7 you could simply create a web.config for each version and then deploy the appropriate version to each IIS web server as needed.

That’s a reasonable solution, but there is a way to use a single web.config to run your ASP.NET app on both IIS6 and IIS7:

  1. Configure your HTTP modules and handlers in *both* the <system.web> and <system.webServer> sections.
  2. Tell IIS7 to skip validation of the Integrated Pipeline mode configuration.

For #2, the way you do that is by adding a <validation> node to your <system.webServer> section and set its validateIntegratedModeConfiguration attribute to false, as such:

If you don’t turn that validation off, IIS7 will try to validate the *configuration* of the Integrated Pipeline mode for your app, which would fail if you have your HTTP modules and handlers also defined in the <system.web> section (because for IIS7 they should only be defined in <system.webServer>). But by turning that validation off, IIS7 won’t throw the error, thus allowing you to get away with defining your HTTP modules and handlers in both places.

The reason this works is because only one set of defined modules and handlers can be loaded. For ASP.NET sites running under IIS6, this will only be the ones defined in <system.web>, which go into the ASP.NET pipeline, while ASP.NET sites in IIS7 will only get the ones defined in <system.webServer>, which actually go into the IIS7 pipeline.

Our complete web.config file now looks like this:

And there you go. Configure your HTTP modules and handlers in both the <system.web> and <system.webServer> sections, turn off validation of the Integrated Pipeline mode, and you can use a single web.config for running ASP.NET sites in IIS6 and IIS7.

… end wayback machine.

Featured Image: Some rights reserved by andrewfhart


  1. Daniil says:

    Hello Dave,

    First of all, thank you for the article! It was really worth to read.

    In the second place, I would like to share some information that you might be interested in. It looks like even having this setting

    we still encounter issues if HTTP handlers and modules are defined in both the sections – and . As a conclusion, it is probably best to avoid having them in both the sections. Either the validateIntegratedModeConfiguration settings cannot handle all possible scenarios or there is a bug in IIS and/or ASP.NET.

    The issues that we encounter (with hyperlinks to relevant posts):

    1. System.OutOfMemoryException

    2. Our custom HTTP handler stops working

    I would appreciate if you could shed some light on that. If you want to investigate the issues in details, please let me know.

    • Hi Daniil – Honestly, I’m not sure why someone would get an OutOfMemoryException or a handler would stop working when defined in both system.web and system.webServer. Like you said, I would need to dig into it and I just don’t have the time for that.

      However, if the app is only ever running on IIS7+, then there is absolutely no reason to bother putting the modules and handlers in both sections. Just put them in system.webServer where they belong and save yourself the headache :-)

Leave a Reply

Your email address will not be published. Required fields are marked *