Chris Cavanagh’s Blog

ASP.NET Routing… Goodbye URL rewriting?

March 11, 2008 · 4 Comments

UPDATE 2: You can find a sample project and more details here.

UPDATE: Be sure to check out Phil Haack’s post covering some of the security implications of this.  I’ve also added a related comment to the end of this post :)

The recent ASP.NET MVC Preview 2 release brought some interesting stuff for “traditional” ASP.NET developers.  The new System.Web.Routing and System.Web.Abstractions assemblies have no dependency on MVC and can be leveraged pretty easily.  Check out this post by Phil Haack (and be sure to keep up with his upcoming posts that will go into more detail).

One of the obvious uses for the new routing mechanism is as a “clean” alternative to URL rewriting (and possibly custom VirtualPathProviders for simple scenarios) for traditional / postback-based ASP.NET sites.  After a little experimentation I found some minimal steps that work pretty well:

  • Create a custom IRouteHandler that instantiates your pages
  • Register new Routes associated with your IRouteHandler
  • That’s it!

The IRouteHandler implementation can be as simple or elaborate as you like.  Just implement the GetHttpHandler method and return a new instance of an ASP.NET page (if you want to use an ASPX you can instantiate it with BuildManager.CreateInstanceFromVirtualPath).

Here’s a very simple IRouteHandler implementation that instantiates a single page (compiled or ASPX) for any request sent to it:

public class WebFormRouteHandler<T> : IRouteHandler where T : IHttpHandler, new()
{
    public string VirtualPath { get; set; }

    public WebFormRouteHandler( string virtualPath )
    {
        this.VirtualPath = virtualPath;
    }

    #region IRouteHandler Members

    public IHttpHandler GetHttpHandler( RequestContext requestContext )
    {
        return ( VirtualPath != null )
            ? (IHttpHandler)BuildManager.CreateInstanceFromVirtualPath( VirtualPath, typeof( T ) )
            : new T();
    }

    #endregion
}

This example could be useful in a site with a single ASPX that hosts multiple ASCXs as its “pages” (maybe one that uses the inbuilt SiteMap as a mapping mechanism between public URLs and ASCXs).  For more traditional sites, your GetHttpHandler would return separate page instances based on the RequestContext it’s provided with (RequestContext includes the routing details extracted from the URL; MVC would create a Controller at this point).

Routes are usually registered in the Application_Start handler in Global.asax.  Here’s a simple example based on the “single ASPX / multiple ASCX” approach that passes several routes to a single page (MyPage.aspx):

protected void Application_Start( object sender, EventArgs e )
{
    RegisterRoutes( RouteTable.Routes );
}

public static void RegisterRoutes( RouteCollection routes )
{
    // Note: Change the URL to “{controller}.mvc/{action}/{id}” to enable
    //       automatic support on IIS6 and IIS7 classic mode

    var routeHandler = new WebFormRouteHandler<Page>( “~/MyPage.aspx” );

    routes.Add( new Route( “{page}”, routeHandler ) );
    routes.Add( new Route( “AccountServices/{page}”, routeHandler ) );
    routes.Add( new Route( “Default.aspx”, routeHandler ) );
}

Phil Haack has a post that covers some security implications of this approach.  Like Phil suggests, the ‘insecure’ behavior might be exactly what you want.  You could prevent direct URL access to your ASPX’s (using ASP.NET’s existing mechanisms) and consider them just resources to be used by your IRouteHandler.

Also note that Phil includes a mechanism for passing the RequestContext to your page (just define and implement the IRoutablePage interface).

Categories: .NET

4 responses so far ↓

Leave a Comment