Life, the Universe, and Software EngineeringLife, the Universe, and Software Engineering

What to you mean IIS can't handle that kind of URL?

Main Image

…or how to take advantage of the IIS 7.0 Integrated Pipeline mode.   In this article we are presenting a module library for IIS 7.0 that gives full control over how IIS handles URLs.  The ASP.NET URLRewriter library allows a web developer to specify and handle just about any type of URL scheme.

With IIS 7.0 you have the option of turning on “Integrated Pipeline mode” which gives you the ability to use the .NET framework to map any URL without the need to change the administrator restricted mime type map.  Traditional asp.net applications could only see and process URLs ending in the classic “.aspx” or “.ashx”, most other URLs were captured by IIS and your application never even saw them. 

There have been a few URL rewrite libraries created over time,  I thought that I would throw my hat into the ring here and create yet another URL rewriter library.

One of the biggest complaints I have about some of the existing URL rewriting schemes in that they tend to put quite an additional load on the processing on each URL.  The URL rewriting library created for this article is designed to take full advantage of ASP caching, so that URL processing happens only once when the URL is encountered for the first time.

On URL Rewriting Verses URL Routing

.NET Framework 3.5 has a new URL Routing scheme that allows the application to programatically redirect URLs to specific HttpModules (see ASP.NET Url Routing for more information on that).  I believe that URL rewrite still has it’s place in the web developers bag of tricks.  In particular URL rewriting plays well with existing applications and does not require hard coding.   This URL rewriting library also has some unique features that provides the ability to capture portions of the URL that the user types and pass them along to your page or handler in the manner similar to the URL routing mechanism.

The URLRewriter Library is Configured in the Web.Config file

First, to use this URLRewriting library you will need to add the DaisleyHarrison.URLRewriter.dll library to your application.  Once you’ve done that, you will need to add a section configuration to the top of your Web.Config file.  For example:

 

<?xml version="1.0"?>

<configuration>
    <configSections>
    … 
        <section name="DaisleyHarrison.UrlRewriter" type="DaisleyHarrison.UrlRewriter.UrlRewriterSection, DaisleyHarrison.UrlRewriter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=86842b37db0c0375" requirePermission="false"/>
    </configSections>
    …
</configuration>

 

 Referencing the DaisleyHarrison.UrlRewriterModule

Then you will need to add two references to the HttpModule in the library that does the actual URL processing.  The first reference is inside the httpModules subsection of the system.web section.  The UrlRewriterModule should be the first module defined in the httpModules section.  The second reference is in the modules subsection of the system.webServer section.  It should also be the first module defined in the modules subsection.  Also note the tag <modules runAllManagedModulesForAllRequests="true"> setting the runAllManagedModulesForAllRequests attribute to true is how the how the IIS 7.0 Integrated Pipeline Mode is turned on.  Turning the Integrated Pipeline Mode on allows the URLRewriter library to map all mime types.

<?xml version="1.0"?>

<configuration>
    <configSections>
    … 
    </configSections>
    <system.web>
        …
        <httpHandlers>
            ...
       </httpHandlers>

        <httpModules>
             <add name="UrlRewriterModule" type="DaisleyHarrison.UrlRewriter.UrlRewriterModule, DaisleyHarrison.UrlRewriter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=86842b37db0c0375"/>
              …
             <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
             …
         </httpModules>
         ….
    </system.web>
    …
    <system.webServer>
        <validation validateIntegratedModeConfiguration="false"/>
        <modules runAllManagedModulesForAllRequests="true">
            <add name="UrlRewriterModule" type="DaisleyHarrison.UrlRewriter.UrlRewriterModule, DaisleyHarrison.UrlRewriter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=86842b37db0c0375"/>
            …
            <remove name="ScriptModule"/>
            <add name="ScriptModule" preCondition="managedHandler" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
        </modules>
        …
    </system.webServer>
     …
</configuration>

 Configuring the URL Rewriter library

Once the URLRewriterModule has been correctly referenced in the Web.Config file. Add the DaisleyHarrison.UrlRewriter section to start configuring the URL rewrite rules.  Below is an excerpt from the sample code that comes with the library. 

<?xml version="1.0"?>

<

configuration>
    <configSections>
    … 
    </configSections>
    <system.web>
        …
    </system.web>
    …
    <system.webServer>
        …
    </system.webServer>
     …
    <DaisleyHarrison.UrlRewriter TraceLevel="Verbose" ApplicationRelative="True">
        <rules>
            <clearRules/>
            <addRule Name="rule1" Pattern="(.*?)\.xxx(.*)" Replace="$1.aspx$2" Disposition="Rewrite"/>
            <addRule Name="rule2" Pattern="(.*?)\.axd(.*)" Disposition="Accept"/>
            <addRule Name="rule3" Pattern="/(?'category'.+?)/(?'action'.+?)/.+\.aspx" When="Match" PassNamedGroups="true" Disposition="Continue"/>
            <addRule Name="rule4" Pattern="(.*)" When="Match,PhysicalFile" Disposition="Accept"/>
            <addRule Name="rule5" Pattern="(.*)" When="Match" Replace="HandlerTest.ashx" Rebase="False" PathInfo="$1"/>
         </rules>
     </DaisleyHarrison.UrlRewriter>
     …
</configuration>

The sample configuration rules

The URL rewriter engine processes rules from the top to bottom.  Rules are match by a combination of a regular expression pattern and one or more conditional When flags.  The default When flag is Match, so rule1 will match any URL with the extension “.xxx”.  In this case, the disposition of rule1 is Rewrite, so the rule will rewrite the URL to a “.aspx” page.  The Replace attribute defines the regular expression replace pattern to defined how the URL will be rewritten.

Rule2 will match any URL with the extension “.axd”.  Since the disposition for rule2 is set to Accept, URLs that match rule2 will be accepted “as is” and passed along to the server unchanged for processing.

Rule3 is a little tricky.  It will match a URL containing any “.aspx” page with two subdirectories from the root. At this time note the that the ApplicationRelative attribute of the DaisleyHarrison.UrlRewriter section is set to true.  This means that all rules are processed as if URL are not absolute, but are relative to the base application URL.  With ApplicationRelative set to true, the application base path is stripped away from the URL prior to processing, then repplied when processing is complete.   This allows rules to be written that will work no matter where the application path actual is.   Getting back to what rule3 actual does: the pattern will be matched for a URL containing a “.aspx” page with two subdirectories of the application root.  Note that in the matching regular expression there are two named capture groups.  One named “category”, and one named “action”.  Since the PassNamedGroups attribute is set to true, whatever parts of the URL match these named groups will  be passed to the final URL as query parameters.  ie.  The final URL will get the query string “?category=door&action=open” added to it.  Also since the Disposition of rule3 is set to Continue, the rest of the rules will continue to be processed.

Rule4 matches any URL that maps to a physical file.  Since rule4 Disposition is set to Accept, the url will be passed on to the server unchanged.

Rule5 is our final URL processing rule.  Rule5 also matches any URL.  The URL is replaced with “HandlerTest.ashx” and the path info for the URL will be set to the orginal URL.  So effectively rule4 and rule5 combined ensure that all URLs that map to physical files will be processed unchanged, and URLs that do not have a physical file will be processed by the HandlerTest.ashx page.

Summary

As you can see, even with just the few rules defined in the sample configuration,  the URL Rewriter library is quite powerful.   The results from the processing of each URL are cached so that each unique URL will be processed only once, delivering a relatively small impact to the URL processing pipeline.   I also include some functionality similar to what can be achieved with the URL Routing feature that is available in .NET 3.5 framework.

There is certainly much more functionality that could be explained here, however, it is better explained in the ASP.NET URLRewriter Library User Guide.

The complete source for this library and the sample code shown in this article are available on the ASP.NET URLRewriter Library Download page.

Authors

All Categories

Archive