Defining Web Forms URL routing in web config

Having worked on a few projects utilizing the new URL routing introduced in ASP.NET 4.0, I have quickly grown tired of specifying my route configurations in the application file (Global.asax). Even on medium-size projects, the list of routes can quickly get out of hand.

I’m not sure why Microsoft team didn’t release a configuration feature for the routing assembly. Regardless, this was something I was itching to do for a while and it turned out to be an easy 6-hour project. My goal was to come up with an easy XML schema as close to the routing API as possible and hopefully not very verbose.

Before going over the capabilities of this tiny library, make sure to download the solution and binaries.

Limitations and Disclaimers

This library will NOT work in the ASP.NET MVC environment as it (MVC) uses a slightly modified API for routing and a different route handler. I don’t do any work in MVC (sadly) and have no plans supporting it. However, it should be a fairly easy task of refactoring.

If you do wind up using this library, use it ‘as is’. I will not be providing any support. All is released under WTFPL license. Lastly, I’d like to say that “IT WORKS ON MY MACHINE!”

The Setup

Nothing new here…

<configSections>
  <section name="routing" type="Routing.Configuration.RoutingConfigurationSection, Routing.Configuration" />
</configSections>

<routing>
  <route></route>
  ...
  <route></route>
</routing>

Defining Simple Routes

Again, very straight-forward. If you’ve done routing in Web Forms, this should be familiar.

<routing>
  <!-- Very simple case -->
  <route name="Default1" url="home" physicalFile="~/Default.aspx" />
  <!-- CheckPhysicalUrlAccess is set to false by default -->
  <route name="Default2" url="home" physicalFile="~/Default.aspx" checkPhysicalUrlAccess="true" />
</routing>

Defining Constraints

Here is an example where the ‘year’ placeholder is constrained to a 4-digit number.

<routing>
  <route name="Archive" url="archive/{year}" physicalFile="~/Archive.aspx">
    <constraints>
      <add placeholder="year" pattern="\d{4}" />
    </constraints>
  </route>
</routing>

If your constraint implements IRouteConstraint, you can define it using ‘type’ attribute.

public class MyTestConstraint : IRouteConstraint
{
    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        return true;
    }
}

And the configuration XML looks like this.

<routing>
  <route name="Archive" url="archive/{year}" physicalFile="~/Archive.aspx">
    <constraints>
      <add placeholder="year" type="MyApplication.MyTestConstraint, MyApplication" />
    </constraints>
  </route>
</routing>

Defining Defaults

In this example, I am setting the ‘year’ placeholder to default value of 2010.

<routing>
  <route name="About" url="archive/{year}" physicalFile="~/Archive.aspx">
    <constraints>
      <add placeholder="year" pattern="\d{4}" />
    </constraints>
    <defaults>
      <add placeholder="year" value="2010" />
    </defaults>
  </route>
</routing>

Defining Data Tokens

<routing>
  <route name="About" url="archive/{year}" physicalFile="~/Archive.aspx">
    <dataTokens>
      <add key="testToken" value="myvalue" />
    </dataTokens>
    <constraints>
      <add placeholder="year" pattern="\d{4}" />
    </constraints>
    <defaults>
      <add placeholder="year" value="2010" />
    </defaults>
  </route>
</routing>

Ignoring Paths

You can specify ignores with or without constraints. Here is one with a single constraint.

<routing>
  <ignore url="{*favicon}">
    <constraints>
      <add placeholder="favicon" pattern="(.*/)?favicon.ico(/.*)?" />
    </constraints>
  </ignore>
<routing>

Finally, here is the snippet which initializes everything. This will appear in your Global.asax file.

void Application_Start(object sender, EventArgs e)
{
    RoutingConfigurationManager.Initialize();
}

Lastly, if you’d rather keep route definitions in a separate file from the main configuration file, you can always do this.

<routing configSource="routing.config"></routing>

<!-- External routing.config -->
<?xml version="1.0" encoding="utf-8" ?>
<routing>
...
</routing>

Make sure to set Copy to Output Directory property of your external file to Copy Always. This concludes my post.