Url rewriting was a weak point for IIS. While Apache Web Server had the mod_rewrite module, for IIS and asp.net web applications not much could be done. Of course, third party solutions existed such as the Url Rewriter or the Url Rewriting HttpModules that provided some functionality for url rewriting. The drawback here was that in every case the .aspx extension was necessary, so that the request was led to the asp.net engine (The request for http://mydomain.com/style.css is not handled by the asp.net engine in IIS6). In order to accomplish extension-less url rewriting to IIS6 or IIS5 you needed to use an ISAPI filter. Although there were some solutions available, in the case of shared hosting servers it was not easy to find one that had such ISAPI filters installed. Read more of this in Scott Guthrie’s article on url rewriting in asp.net 2.0.
When IIS7 was released, a built-in url rewriting module appeared which made things much easier for asp.net developers. One good thing about IIS7, is that all requests go through the asp.net engine. so we can now easily perform extension-less url rewriting tasks. Using regular expressions we can create our rules. With little googling you can come up with a lot of small and easy examples on this subject.
Recently, I made my first set of rules. All ran smoothly except from two basic points. My first approach was to create a rule that the url http://mydomain.com/contact to be rewritten to http://domain.com/default.aspx?title=contact. A simple rule would be able to complete this task. The rule I came up was:
<rewrite> <rules> <rule name="Rewrite content"> <match url="^([._0-9a-z-]+)" /> <action type="Rewrite" url="default.aspx?title={R:1}" /> </rule> </rules> </rewrite> |
Please notice that in the matching characters is the ‘.’. This complicates things a bit since all requests for .htm, .js, .css were handled by this rule and the default.aspx page loaded with an invalid title in the query string (oops!). One solution is to write rules that wont allow rewriting for the extensions you don’t want to. An other approach that I found more elegant is to change the above rule and if the original url is an existing file or folder the rewriting rule wont apply. The above rule changed to something like this:
<rewrite> <rules> <rule name="Rewrite content"> <match url="^([._0-9a-z-]+)" /> <conditions logicalGrouping="MatchAll"> <add matchType="IsFile" negate="true" /> <add matchType="IsDirectory" negate="true" /> </conditions> <action type="Rewrite" url="default.aspx?title={R:1}" /> </rule> </rules> </rewrite> |
The second thing I sot stuck is that the /WebResource.axd?d=… and the /ScriptResource.axd?d=… references that are generated by the asp.net engine would be rewritten. The result was some missing css declarations and a JavaScript error that Sys is not defined, which means that the asp.net ajax engine failed to load. In order to fix this, an extra line is required to the above rule so that all the .axd requests will be excluded by this rule.
<rewrite> <rules> <rule name="Rewrite content"> <match url="^([._0-9a-z-]+)" /> <conditions logicalGrouping="MatchAll"> <add input="{URL}" negate="true" pattern="\.axd$" /> <add matchType="IsFile" negate="true" /> <add matchType="IsDirectory" negate="true" /> </conditions> <action type="Rewrite" url="default.aspx?title={R:1}" /> </rule> </rules> </rewrite> |
I think that this is a rather good approach in the case of an existing web site that url rewriting must be applied. Telling the IIS to exclude all requests that are actual files not to be processed is a very quick and generic way to avoid the scenario that all static content is mapped to default.aspx. There is a catch though, if there are many broken links to your web page this rule would cause to load the default.aspx more than once. This could easily lead to a performance bottleneck. A safer approach is to add a prefix to your urls, e.g. http://mydomain.com/content/contact or http://mydomain.com/article/123/my-title. With this apporach your url rewriting rules will be more solid and hide less surprises. Also, the second suggestion saves you the query to the database to get the id of the article
.
Update: Here are a couple of simple but useful rules that I use in every website I make. The first is to redirect all url’s that do not start with www. to their www. equivalent. The second rule is to remove any trailing slash at the end of any url.
<rule name="non www to www" enabled="true"> <match url="(.*)" /> <conditions> <add input="{HTTP_HOST}" negate="true" pattern="^www\.([.a-zA-Z0-9]+)$" /> </conditions> <action type="Redirect" url="http://www.{HTTP_HOST}/{R:0}" appendQueryString="true" redirectType="Permanent" /> </rule> <rule name="Remove trailing slash" stopProcessing="true"> <match url="(.*)/$" /> <conditions> <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" /> <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" /> </conditions> <action type="Redirect" redirectType="Permanent" url="{R:1}" /> </rule> |
You can also check these links below:
Thank you SO much for this very informative article. I had searched so long for the solution to the .axd files being re-written. My site is running with AJAX and URL rewrite working hand-in-hand. Cheers!