Wildcard script mapping and IIS 7 integrated pipeline

The big benefit of IIS 7 integrated request processing pipeline is the fact that all the nice and useful ASP.NET features can be used for any type of content on your web site; not just for ASP.NET-specific content. For example, ASP.NET SQL-based membership can be used to protect static files and folders. Also, ASP.NET extensibility API’s, such as IHttpHandler and IHttpModule can be used to add custom modules and handlers that would be executed even for non-ASP.NET content.

IIS 6 did not have this level of integration. ASP.NET was plugged into IIS 6 as an ISAPI extension and by default was configured to handle ONLY requests mapped to that extension – for example any request that ended with “.aspx” would be be processed by ASP.NET extension. This obviously was a big limitation for customers who wanted to be able to use ASP.NET features for all other contend on web site. The most common way to workaround that was to use “Wildcard script mapping”. This post explains how an application that used wildcard script mapping in IIS 6 can be migrated over to IIS 7.

Assume you had configured ASP.NET in IIS 6 to handle all requests by using wildcard script mapping. For example you had an ASP.NET module for URL rewriting and you wanted this module to handle extension-less URLs.

This wildcard script map configuration is typically done within IIS 6 manager by opening the properties dialog for either web server or web site and selecting Home Directory tab, then clicking on Configuration button and then clicking on the Insert button for “Wildcard application maps”:

WildcardIIS6

Now, as you move your application to IIS 7, you want to configure it to achieve the same behavior of ASP.NET. There are two options on how this can be done: using Classic pipeline mode or using Integrated pipeline mode.

Wildcard script mapping in IIS 7 classic pipeline mode

With classic pipeline mode the ASP.NET is plugged into the IIS request processing pipeline as an ISAPI extension – exactly the same way as it was in IIS 6. In fact, if you open %WINDIR%\system32\inetsrv\config\applicationHost.config file and locate the <handlers> section inside of it you can see how IIS is configured to map ASP.NET specific requests to the aspnet_isapi.dll:

<handlers accessPolicy="Read, Script">
  ...
  <add name="PageHandlerFactory-ISAPI-2.0"
       path="*.aspx" verb="GET,HEAD,POST,DEBUG"
       modules="IsapiModule"
       scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll"
       preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
  ...
</handlers>

Notice the preCondition attribute for the handler mapping. Among other things this attribute is set to classicMode, which ensures that this handler mapping only takes effect when the application pool is configured to run in classic mode.

Now if you want to configure wildcard mapping for the ASP.NET running in classic mode, you can add one more handler mapping to the <handlers> section just before the handler mapping for static files:

<handlers accessPolicy="Read, Script">
  ...
  <add name="ASP.NET-ISAPI-2.0-Wildcard"
     path="*" verb="GET,HEAD,POST,DEBUG"
     modules="IsapiModule"
     scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll"
     preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
  <add name="StaticFile"
     path="*" verb="*"
     modules="StaticFileModule,DefaultDocumentModule,DirectoryListingModule"
     resourceType="Either" requireAccess="Read" />
</handlers>

The relative order of the wildcard handler mapping is important: if you define this handler mapping after the “StaticFile” handler mapping then “StaticFile” will handle all the requests and no requests will ever come to ASP.NET wildcard handler.

As you may already know the ASP.NET wildcard handler mapping in IIS 7 is subject to the same performance limitations as existed in IIS 6. The problem with this kind of handler mapping is that ALL requests are processed by it, including requests for static files. The ASP.NET static file handler is not as powerful as native IIS static file handler. Plus static files served by ASP.NET will not be cached by IIS in kernel mode. Because of these performance limitations it is recommended that you use IIS 7 integrated pipeline to achieve the same functionality as with wildcard mappings in IIS 6.

IIS 7 integrated pipeline instead of wildcard script mapping

With integrated pipeline, the ASP.NET functionality is fully integrated into the main request processing in IIS, which means that all ASP.NET features are now available for any type of requests. This effectively eliminates the need for the wildcard handler mapping. Now you can use your existing ASP.NET modules and have them applied to all requests.

For example let’s say you had a URL rewriting module written in ASP.NET. On IIS 6 this module was registered inside of the <system.web> section in web.config file as below:

<system.Web>
  <httpModules>
    ...
    <add name="MyUrlRewrite"
         type="SomeNamespace.MyModules.UrlRewrite, SomeNamespace.MyModules" />
    ...
  </httpModules>
</system.Web>

Since on IIS 6 this module was only executed for requests to managed content, it only worked for URLs that had .aspx extension, such as http://example.com/archive/2008/08/26/post-title.aspx. If you wanted it to handle extension-less URLs you had to configure wildcard script mapping for ASP.NET. With IIS 7 integrated pipeline you do not have to do that anymore. In order to make this module apply to extension-less URLs you need to register it within the <system.webServer> section inside of web.config file as below:

<system.webServer>
  <modules >
    ...
    <add name="MyUrlRewrite"
         type="SomeNamespace.MyModules.UrlRewrite, SomeNamespace.MyModules"
         preCondition="" />
    ...
  </modules>
<system.webServer>

Make sure that you leave the preCondition attribute empty here as it would enforce that the module will be executed for all requests, not just for requests for ASP.NET specific content.

Registering your managed modules this way does not have such dramatic performance impact as when using wildcard script mappings. Even though the module is invoked for all requests to web application, all the existing handler mappings are still in effect, which means that the static files are still served by the native IIS static file handler. Another benefit of registering your module this way is that now it can be applied to requests for PHP, ASP or any other dynamic pages. You would not be able to do that if you used wildcard script mappings.

One last thing to mention here is that you can also use the attribute on the <modules> section called runAllManagedModulesForAllRequests.

<system.webServer>
  <modules runAllManagedModulesForAllRequests="True" >
    ...
    <add name="MyUrlRewrite"
         type="SomeNamespace.MyModules.UrlRewrite, SomeNamespace.MyModules"
         preCondition="ManagedHandler" />
    ...
  </modules>
<system.webServer>

This attributes forces IIS to ignore the preCondition=”managedHandler” attribute, hence all managed modules will be invoked for all requests to web application.

25 thoughts on “Wildcard script mapping and IIS 7 integrated pipeline”

  1. Hi,

    I liked your article. It gave me a better understanding of IIS 7.

    I am in a similiar scenario to the one you mentioned, that is i have an asp.net module for url rewriting and had wild card mapping in IIS 6.

    I had extensionless url’s .. like http://www.xxx.com/sports which got mapped to http://www.xxx.com/sports/pag1.aspx

    and I had extension url’s … like http://www.xxx.com/sports/football.aspx which got mapped to http://www.xxx.com/sports/default.aspx?Sport=football

    Now i’m trying to move to IIS 7 and i couldn’t get the url rewriter to work at all. Neither the extionless urls or the extension urls which used url’s rewriting worked.

    I read your article and tried the classic mode approach. The extension url’s like http://www.xxx.com/sports/football.aspx started working. But the extensionless url’s like http://www.xxx.com/sports would get redirected to http://www.xxx.com/sports/ and the http://www.xxx.com/sports/default.aspx would be shown.

    I was wondering if you had any idea of what i’m doing wrong.

    Thnx,

    Tarique

  2. Hi again,

    I tried using the integrated pipeline approach. Like in the previous case, the extensions with url’s are getting rewritten properly.

    However, again having problem with extensionless url’s:

    This time if i type in http://www.xxx.com/sports, i get the error:

    System.Web.HttpException: Session state can only be used when enableSessionState is set to true, either in a configuration file or in the Page directive. Please also make sure that System.Web.SessionStateModule or a custom session state module is included in the \\ section in the application configuration.

    Again if i type in the real page name http://www.xxx.com/sports/page1.aspx, it shows up fine.

    Any idea of what i’m doing wrong ?

  3. Hi,

    I tried the runAllManagedModulesForAllRequests=”true” and got it to work.

    Do you know what this attribute does ?(Will it have a performance impact? and why i got the error message without the tag?

    Also, any ideas on how i could get the wild card mapping to work in the classic mode ?

    I’d appreciate any help you could give me.

  4. I think you’ve got the error message before because your application was relying on some other managed module (Session) and that module was configured to run only for requests to managed handler.

    You can try the following steps:
    1. Remove the runAllManagedModulesForAllRequests attribute (or set it to false).
    2. Re-configure the Session module to run for all requests:

    <modules>
    <remove name="Session" />
    <add name="Session" type="System.Web.SessionState.SessionStateModule" preCondition="" />
    </modules>

  5. Hi! I went the classic pipeline way, but had problems with my static files (.css,.js,.jpg,.gif et.c). My solution was to add static handlers for each extension above the isapi handler. Was there another option?

  6. Hello,

    Thank you for this post. It is very informative and extremely helpful, especially for those who are moving or have just moved to IIS 7 and have not yet had time to fully understand IIS 7.

    Best wishes,
    George

  7. Mine doesn’t work either even with runAllManagedModulesForAllRequests=”true”. It used to work before but now nothing gets to the httpmodule on iis7. Maybe some updates to iis7 caused it to stop working?

  8. Hi

    im using IIS 7, having the trouble in redirecting the page when user use http://flixmediastation.com, acctually it has to redirect to
    http://www.flixmediastation.com

    to be very frank i followed the instructions given, it was working very fine in the IIS7 local server in all above mentioned bugs and it was not working the live one when i use http://flixmediastation.com its redirecting to flixmediastation.com and stopped

    this was the rule im follwing ,please try to get me rid out of this.

    Thanks in advance,

    Simon Patrick.

  9. I simply changed the application pool of the website to default application pool ( Classic dot Net) and It worked.

    Changing the current application to classical mode didn’t solve it.

  10. As Aneesh said, you need to use “DefaultAppPool” at “Basic Settings” “Actions Menu”.

    Thank you for that great article, it helped me A LOT.

  11. Sorry for commented on such an old post but it seems to be exactly what I’m looking for.

    Currently I’m just trying to get a test site up and running, this site has a module written as well as a handler. I was able to get the handler running in the section which means it only handled .aspx requests. I then enabled the module and moved it to the section but I can’t seem to get it to work. It appears to not intercept at all, if I punch in the http://url/products/ I get the default page in that folder, if I try http://url/products/beverages.aspx I get a 404 error.

    I’ve tried enabling the module, the handler. I’ve tried adding the “runAllManagedModulesForAllRequests” flag. I tried adding in the session module. I’ve reordered the modules.

    Here is my current web.config web server section (sorry if it comes out a mess):

    Any help would be appreciated 🙂

  12. Sorry, forgot to encode my config file:
    <system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    <modules runAllManagedModulesForAllRequests="true">
    <remove name="ScriptModule" />
    <remove name="MyURLRewriter" />
    <remove name="Session"/>
    <add name="MyURLRewriter" type="URLRewriter.ModuleRewriter, URLRewriter" preCondition="ManagedHandler" />
    <add name="ScriptModule" preCondition="managedHandler" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    <add name="Session" type="System.Web.SessionState.SessionStateModule" preCondition=""/>
    </modules>
    <handlers>
    <remove name="WebServiceHandlerFactory-Integrated" />
    <remove name="ScriptHandlerFactory" />
    <remove name="ScriptHandlerFactoryAppServices" />
    <remove name="ScriptResource" />

    <add name="ScriptHandlerFactory" verb="*" path="*.asmx" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    <add name="ScriptHandlerFactoryAppServices" verb="*" path="*_AppService.axd" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    <add name="ScriptResource" verb="GET,HEAD" path="ScriptResource.axd" preCondition="integratedMode" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    <!–<add name="URLRewriter" type="URLRewriter.RewriterFactoryHandler, URLRewriter" preCondition=""/>–>
    </handlers>
    </system.webServer>

  13. I found my problem. It seems that if you run the debugger it uses the Cassini web server instead of IIS therefore the module never gets hit when using the integrated pipeline method.

    I guess if I need to debug my module I’ll have to move it to the system.web section, debug, fix and move back to system.webServer.

    Hopefully this helps someone else out there, it was quite frustrating, especially after I just created a simple walk through project and it still wasn’t working.

  14. Hi,

    My case i have separate class for handle URL-Rewrite which is inside App_Code, i did the necessary changes in my web.config, but still i get the following error.

    HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled

    Note – Im using Integrated Mode.

  15. This article is just like every other article on the net dealing with IIS 7.x and IHttpModule — all of them claim to work for static content, and none of them do.

    If anyone out there has a real, working solution for this problem I’d sure like to hear about it.

    And please, do NOT post Yet Another Link to another useless and dead wrong “article” claiming that something like the steps above will work, because none of them do. I’d like a real, functioning, complete end-to-end project file that shows me EVERYTHING involved in getting IHttpModule to intercept EVERY MIME type there is, and not just the HTML from an ASPX file.

    The MSDN documentation is also completely worthless when it comes to this. The same dead wrong examples, and the same generic blather and hand-waving about “just include in web.config”.

    Thing is, I really REALLY need to figure out how to get this working. I need to be able to intercept *ALL* text-type content (HTML, CSS, etc.) on the way back to the client so that I can rewrite parts of the content (to remap content for a CDN, not something scammy like spam).

    Is there a WORKING alternative to using IHttpModule? I’d prefer to use a Filter if I can, because I’ve already written something exactly like what I want using Java for Apache/Tomcat and would like to just port my existing code.

    Any CORRECT and REAL help with this would be appreciated.

    Jerry H.

  16. Your article is good.
    I am new to IIS 7 url rewriting module. I followed the steps to write rules and store in Sql server it worked fine. i followed

    http://learn.iis.net/page.aspx/803/using-custom-rewrite-providers-with-url-rewrite-module/

    I am able to get “http://localhost:9090/Home/Default.aspx” when i request IIS 7 for “http://localhost:9090/Home/Default” but all other links (say “http://localhost:9090/point) will be shown as “http://localhost:9090/Home/point” . it tales the relative path with respect to the current URL in address bar.

    may be i am missing something obvious here.
    Please help.

    Thanks,

  17. Haѵe you eѵer thought about creatіng an e-book ог guest аuthoring οn
    other wеbsіtеs? Ӏ have a blog basеd on the samе topics you ԁiscuss and would really likе to
    have you ѕharе some stогiеs/information.
    I know mу reaԁers wоuld νalue your wοrk.
    If you’re even remotely interested, feel free to send me an e mail.

Leave a Reply

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