Some notes on routing in classic ASP.NET web applications

Routing in .NET 3.5 SP1 differs from regular request handling in many ways. Here’s a quick outline how routing works:

  1. Routes define some URL matching pattern and are configured/held in an ordered list accessible through RouteTable.Routes
  2. Incoming requests pass through the UrlRoutingModule that will walk the route table and will try to find the first match
  3. If a match was made, the route can extract values from the URL and store these in a RouteData object under the Values properties (there is more to store in a RouteData, but that’s beyond the basics)
  4. Assuming a match was made, the route determines the HTTP handler class
  5. The HTTP handler is passed the RouteData and is called to handle the request.

When you use System.Web.Routing in a “classic” web application, you will need a special kind of http handler class to leverage the new RouteData. (Quick tip: you might not need the Request.QueryString in your handler any more, as you can extract that information when determining the route data.). For Web Forms you can find the WebFormRouteHandler implementation in the “Using Routing with WebForms” article by Phil Haack. The route handler by Phil expects the interface IRoutablePage on the web page so it can stick the RequestContext in it (step 4-5).

But, as soon as you have a custom http handler implementation, you are left empty handed again.

image

Phil’s implementation assumes two things:

  • A System.Web.UI.Page derived class.
  • A registered http handler endpoint (either through an .ashx file or via web.config’s <httpHandlers> section)

There is a quick fix for Phil’s code for the first bullet: simply change line 46 to become:

var page = BuildManager.CreateInstanceFromVirtualPath(virtualPath, typeof(IRoutablePage)) as IHttpHandler;

I would also recommend changing some names. The IRoutablePage interface could be IRoutableHttpHandler and the WebFormRouteHandler could be ClassicRouteHandler, or whatever tickles your fancy.

Bullet 2 is hard to bypass. You need to make peace with that assumption. It should be OK for everyday scenarios.

To complement this, I quickly wrote up a generic base class and corresponding interface to allow you to write a custom handler using System.Web.Routing without the need to have this registered anywhere. This will give you tremendous freedom for hooking up a custom HTTP handler. (You will have to come up with an example, because I can’t think of one, except you or me being too lazy to do the registration in the web.config. Well, I can, but that involves some crazy on-the-fly generation of handlers that no-one wants. Or do they?)

The interface IRoutableHttpHandler should be implemented by the HTTP handler instead of IHttpHandler.

public interface IRoutableHttpHandler : IHttpHandler

{

  RequestContext RequestContext { get; set; }

}

Very similar to the IRoutablePage of Phil (it is exactly similar if you followed my suggested renaming of his code).

public class MySuperbadCustomHandler : IRoutableHttpHandler

{

  public void ProcessRequest(HttpContext context)

  {

    context.Response.ContentType = “text/plain”;

    context.Response.Write(“I’m superbad”);

  }

 

  public bool IsReusable

  {

    get { return false; }

  }

 

  #region IRoutableHttpHandler Members

 

  public RequestContext RequestContext { get; set; }

 

  #endregion

}

Above is a rather silly custom HTTP handler, but it should be clear where to put your stuff. (No, I’m not telling)

The generic route handler looks like this:

public class GenericHttpRouteHandler<T> : IRouteHandler

  where T : IRoutableHttpHandler, new()

{

  #region IRouteHandler Members

 

  public IHttpHandler GetHttpHandler(RequestContext requestContext)

  {

    T handler = new T();

    handler.RequestContext = requestContext;

    return handler;

  }

 

  #endregion

}

Your route should use this handler and specify the custom HTTP handler as the generic T type. Here’s a sample:

routes.Add(new Route(“sweet”, new GenericHttpRouteHandler<MySuperbadCustomHandler>()));

Small and simple, so there must be a catch. Yep, there is one major one: without a known endpoint it is hard to do the authorization (file or url) based access checks. So, in essence anyone can access the HTTP handler. Not to be used for secured resources. You have been warned.

Advertisements
This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s