Académique Documents
Professionnel Documents
Culture Documents
<urlMappings enabled="true">
</urlMappings>
</form>
Thus, URL mapping available in ASP.NET 2.0 is almost always useless. It would be much better to be able to
specify a set of similar URLs in one mapping rule. The best solution is to use Regular Expressions (for
overview see Wikipedia and for implementation in .NET see MSDN), but an ASP.NET 2.0 mapping does not
support regular expressions. We therefore need to develop a different solution to built-in URL mapping.
<rewriteModule>
<rewriteOn>true</rewriteOn>
<rewriteRules>
<rule source="(\d+)/(\d+)/(\d+)/"
destination="Posts.aspx?Year=$1&Month=$2&Day=$3"/>
<rule source="(.*)/Default.aspx"
destination="Default.aspx?Folder=$1"/>
</rewriteRules>
</rewriteModule>
This means that all requests that run like: http://localhost/Web/2006/12/10/ should be internally redirected
to the page Posts.aspx with query string parameters.
Please note that web.config is a well-formed XML file, and it is prohibited to use the symbol & in attribute
value strings. In this case, you should use & instead in the destination attribute of the rule element.
To use the rewriteModule section in the web.config file, you need to register a section name and a section
handler for this section. To do this, add a configSections section to web.config:
<sectionGroup name="modulesSection">
</sectionGroup>
</configSections>
This means you may use the following section below the configSections section:
<modulesSection>
<rewriteModule>
<rewriteOn>true</rewriteOn>
<rewriteRules>
<rule source="(\d+)/(\d+)/(\d+)/"
destination="Post.aspx?Year=$1&Month=$2&Day=$3"/>
<rule source="(.*)/Default.aspx"
destination="Default.aspx?Folder=$1"/>
</rewriteRules>
</rewriteModule>
</modulesSection>
Another thing we have to bear in mind during the development of the rewriting module is that it should be
possible to use 'virtual' URLs with query string parameters, as shown in the following: http://
www.somebloghost.com/2006/12/10/?Sort=Desc&SortBy=Date. Thus we have to develop a solution that
can detect parameters passed via query string and also via virtual URL in our web application.
Figure 1
So, let’s start by building a new Class Library. We need to add a reference to the System.Web assembly, as
we want this library to be used within an ASP.NET application and we also want to implement some web-
specific functions at the same time. If we want our module to be able to read web.config, we need to add a
reference to the System.Configuration assembly.
using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration;
using System.Web;
using System.Xml;
namespace RewriteModule
// application root
// from web.config
try
_RewriteOn = Convert.ToBoolean(
section.SelectSingleNode("rewriteOn").InnerText);
}
catch (Exception ex)
return this;
The Class RewriteModuleSectionHandler will be initialized by calling the Create method with the
rewriteModule section of web.config passed as XmlNode. The SelectSingleNode method of the XmlNode
class is used to return values for module settings.
http://www. somebloghost.com/gaidar/?Folder=Blogs
and the result will be the same as if you used this URL:
http://www. somebloghost.com/Blogs/gaidar/
To resolve this issue, we have to create some kind of wrapper for 'virtual path parameters'. This could be a
collection with a static method to access the current parameters set:
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections.Specialized;
using System.Web;
namespace RewriteModule
get
if(HttpContext.Current.Items.Contains("RewriteContextInfo"))
return (RewriteContext)HttpContext.Current.Items["RewriteContextInfo"];
else
public RewriteContext()
_InitialUrl = String.Empty;
_InitialUrl = url;
}
}
Rewriting URLs
Now let's try some rewriting. First, we need to read rewriting rules from the web.config file. Secondly, we
need to check the actual URL against the rules and, if necessary, do some rewriting so that the appropriate
page is executed.
We create an HttpModule:
{}
When adding the RewriteModule_BeginRequest method that will process the rules against the given URL,
we need to check if the given URL has query string parameters and call HttpContext.Current.RewritePath to
give control over to the appropriate ASP.NET page.
using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Configuration;
using System.Xml;
using System.Text.RegularExpressions;
using System.Web.UI;
using System.IO;
using System.Collections.Specialized;
namespace RewriteModule
// it is necessary to
if (!cfg.RewriteOn) return;
if (path.Length == 0) return;
try
if (match.Success)
path = re.Replace(
path,
xml.Attributes["destination"].InnerText);
if (path.Length != 0)
if(HttpContext.Current.Request.QueryString.Count != 0)
HttpContext.Current.Items.Add(
"OriginalUrl",
HttpContext.Current.Request.RawUrl);
// rewrite
HttpContext.Current.RewritePath(rew);
return;
return;
But this is just half of the road we need to go down, because the rewriting module should handle a web
form's postbacks and populate a collection of 'virtual path parameters'. In the given code you will not find a
part that does this task. Let's put 'virtual path parameters' aside for a moment. The main thing here is to
handle postbacks correctly.
If we run the code above and look through the HTML source of the ASP.NET page for an action attribute of
the form tag, we find that even a virtual URL action attribute contains a path to an actual ASP.NET page. For
example, if we are using the page ~/Posts.aspx to handle requests like http://www. somebloghost.com/
Blogs/2006/12/10/Default.aspx, we find the action="/Posts.aspx". This means that the user will be using
not the virtual URL on postback, but the actual one: http://www. somebloghost.com/Blog.aspx. This is not
what we want to use here! So, a few more lines of code are required to achieve the desired result.
First, we must register and implement one more method in our HttpModule:
// it is necessary to
}
}
This method checks if the user requested a normal ASP.NET page and adds a handler for the PreInit event of
the page lifecycle. This is where RewriteContext will be populated with actual parameters and a second URL
rewriting will be performed. The second rewriting is necessary to make ASP.NET believe it wants to use a
virtual path in the action attribute of an HTML form.
if (HttpContext.Current.Items.Contains("OriginalUrl"))
HttpContext.Current.Items["RewriteContextInfo"] = con;
if (path.IndexOf("?") == -1)
path += "?";
HttpContext.Current.RewritePath(path);
To use RewriteModule in a web application, you should add a reference to the rewrite module assembly and
register HttpModule in the web application web.config file. To register HttpModule, open the web.config
file and add the following code into the system.web section :
<httpModules>
</httpModules>
Using RewriteModule
There are a few things you should bear in mind when using RewriteModule:
* It is impossible to use special characters in a well-formed XML document which is web.config in its
nature. You should therefore use HTML-encoded symbols instead. For example, use & instead of &.
* To use relative paths in your ASPX pages, you should call the ResolveUrl method inside HTML tags:
<img src="<%=ResolveUrl("~/Images/Test.jpg")%>" />. Note, that ~/ points to the root directory of
a web application.
* Bear in mind the greediness of regular expressions and put rewriting rules to web.config in order of
their greediness, for instance:
<rule source="Directory/(.*)/(.*)/(.*)/(.*).aspx"
destination="Directory/Item.aspx?
Source=$1&Year=$2&ValidTill=$3&Sales=$4"/>
<rule source="Directory/(.*)/(.*)/(.*).aspx"
destination="Directory/Items.aspx?
Source=$1&Year=$2&ValidTill=$3"/>
<rule source="Directory/(.*)/(.*).aspx"
destination="Directory/SourceYear.aspx?
Source=$1&Year=$2&"/>
<rule source="Directory/(.*).aspx"
destination="Directory/Source.aspx?Source=$1"/>
* If you would like to use RewriteModule with pages other than .aspx, you should configure IIS to map
requests to pages with the desired extensions to ASP.NET runtime as described in the next section.
Then click the Configuration… button on the Virtual Directory tab (or the Home Directory tab if you are
configuring mappings for the website).
If you would like to map all extensions to ASP.NET, then for IIS 5 on Windows XP you have only to map .*
extension to the ASP.NET ISAPI extension. But for IIS 6 on Windows 2003 you have to do it in a slightly
different way: click on the Insert… button instead of the Add… button, and specify a path to the ASP.NET
ISAPI extension.
Conclusions
Now we have built a simple but very powerful rewriting module for ASP.NET that supports regular
expressions-based URLs and page postbacks. This solution is easily implemented and gives users the ability
to use short, neat URLs free of bulky Query String parameters. To start using the module, you simply have
to add a reference to the RewriteModule assembly in your web application and add a few lines of code to the
web.config file, whereupon you have all the power of regular expressions at your disposal to override URLs.
The rewrite module is easily maintainable, because to change any 'virtual' URL you only need to edit the
web.config file. If you need to test your application without the module, you can turn it off in web.config
without modifying any code.
To gain a deeper insight into the rewriting module, take a look through the source code and example attached
to this article. I believe you'll find using the rewriting module a far more pleasant experience, than using the
native URL mapping in ASP.NET 2.0.
Gaidar Magdanurov, an MVP for Visual Basic, lives in Moscow. His primary job is scientific research in
INEOS RAS. Gaidar also works as a software developer/consultant and is editor-in-chief of the VBStreets
web site, dedicated to Visual Basic and Microsoft .NET technologies. An active member of the Russian
GotDotNet community, Gaidar also enjoys speaking at user-group meetings. In his spare time, Gaidar likes
playing the guitar, going to the theatre, walking in the park and visiting friends.
This article first appeared on Simple Talk (http://www.simple-talk.com/default.aspx) and is reproduced
with kind permission of the editor.