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

by Aaron D-H 8. June 2009 20:17

…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.

Tags:

Software Engineering | .NET | C# | Visual Basic | ASP.NET

Comments


June 9. 2009 08:33
trackback
Trackback from DotNetKicks.com

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


June 9. 2009 23:41
trackback
Trackback from Web Development Community

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


June 17. 2009 11:39
Terry Walker
Good post, but have you thought about The sample configuration rules before?


June 17. 2009 19:52
aarondh
Well your right it is a simple set of rules, and they have been tested in the sample app.  If you are interested here are the rules I'm using on this site.  They are using a later version of the library then was used in this article.

  <DaisleyHarrison.UrlRewriter>
    <rules>
      <clearRules/>
      <addRule Name="blog1" Host="blog.daisley-harrison.com" Pattern="/blog$" Replace="/blog/default.aspx" Disposition="Accept"/>
      <addRule Name="blog2" Host="blog.daisley-harrison.com" Pattern="/blog/$" Replace="/blog/default.aspx" Disposition="Accept"/>
      <addRule Name="blog3" Host="blog.daisley-harrison.com" Pattern="/blog/.*" Disposition="Accept"/>
      <addRule Name="blog4" Host="blog.daisley-harrison.com" Pattern=".*" Replace="/blog$0" Disposition="Rewrite"/>
      
      <addRule Name="blog5" Host="blog.daisley-harrison.net" Pattern="/blog/.*" Disposition="Accept"/>
      <addRule Name="blog6" Host="blog.daisley-harrison.net" Pattern=".*" Replace="/blog$0" Rebase="false" Disposition="Rewrite"/>
      
      <addRule Name="support1" Host="support.daisley-harrison.com" Pattern="/$" Replace="/wiki/support.ashx" Disposition="Redirect"/>
      <addRule Name="support2" Host="support.daisley-harrison.net" Pattern="/$" Replace="/wiki/support.ashx" Disposition="Redirect"/>
      
      <addRule Name="wiki1" Host="wiki.daisley-harrison.com" Pattern="/$" Replace="/wiki/default.aspx" Disposition="Redirect"/>
      <addRule Name="wiki2" Host="wiki.daisley-harrison.net" Pattern="/$" Replace="/wiki/default.aspx" Disposition="Redirect"/>
      

      <addRule Name="aaron1" Host="aaron.daisley-harrison.com" Pattern="/blog/.*" Disposition="Accept"/>
      <addRule Name="aaron2" Host="aaron.daisley-harrison.com" Pattern=".*" Replace="/blog$0" Rebase="false" Disposition="Rewrite"/>
      
      <addRule Name="aaron3" Host="aaron.daisley-harrison.net" Pattern="/blog/.*" Disposition="Accept"/>
      <addRule Name="aaron4" Host="aaron.daisley-harrison.net" Pattern=".*" Replace="/blog$0" Disposition="Rewrite"/>
    </rules>
  </DaisleyHarrison.UrlRewriter>


June 17. 2009 19:53
aarondh
I should point out that the latest feature I've added for the above rule set is the ability to handle host headers.


July 19. 2009 20:09
aarondh
Thanks I did use BlogEngine.  BlogEngine actual is an open source application that runs on Microsoft products.  BlogEngine is not from Microsoft.  You can read more about BlogEngine at http://www.dotnetblogengine.net/


July 22. 2009 19:08
aarondh
Check out this article in technet on application pool settings.
www.microsoft.com/.../...6d-b3ba-bda04061a5e7.mspx


October 21. 2009 16:57
Tom
The URL Rewriter library is very powerful because of the few rules defined in the sample configuration. Processing each URL on cached with each unique URL only at once and delivering a relatively small impact to the URL processing pipeline was really easy.


August 8. 2010 13:22
Lea Grinnell
Thanks for taking made the effort to discuss regular expression, I feel powerfully regarding it and love learning additional on this subject. If likely, since you gain expertise, would u mind updating your internet site with extra information? Extremely helpful 4 me.

Comments are closed

About the Author

I'd like to introduce myself to you... My name is Aaron Daisley-Harrison.  I have worked in the software engineering field for a number of years, and as an  Application Architect have created solutions for many industry verticals; worked with both Java and Microsoft technologies; Developed SQL database engines as well as full text search systems; and Knowledge management systems.   I am currently doing contract work out of the Pacific North West and have lately been focusing on Microsoft technologies like SharePoint 2007/2010, WCF, Identity Framework, JQuery, Xml and Silverlight.
[more]



 Digg!

 

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2009 Aaron G. Daisley-Harrison - All Rights Reserved.