A RouteHandler for IHttpHandlers

asp.net, code 0 comments suggest edit

This code has been incorporated into a new RouteMagic library I wrote which includes Source Code on CodePlex.com as well as a NuGet package!

I saw a bug on Connect today in which someone offers the suggestion that the PageRouteHandler (new in ASP.NET 4) should handle IHttpHandler as well as Page.

I don’t really agree with the suggestion because while a Page is an IHttpHandler, an IHttpHandler is not a Page. What I this person really wants is a new handler specifically for http handlers. Let’s give it the tongue twisting name: IHttpHandlerRouteHandler.

Unfortunately, it’s too late to add this for ASP.NET 4, but it turns out such a thing is trivially easy to write. In fact, here it is.

public class HttpHandlerRouteHandler<THandler> 
    : IRouteHandler where THandler : IHttpHandler, new() {
  public IHttpHandler GetHttpHandler(RequestContext requestContext) {
    return new THandler();
  }
}

Of course, by itself it’s not all that useful. We need extension methods to make it really easy to register routes for http handlers. I wrote a set of those, but will only post two examples here on my blog. To get the full set download the sample project at the very end of this post.

public static class HttpHandlerExtensions {
  public static void MapHttpHandler<THandler>(this RouteCollection routes,     string url) where THandler : IHttpHandler, new() {
    routes.MapHttpHandler<THandler>(null, url, null, null);
  }
  //...
  public static void MapHttpHandler<THandler>(this RouteCollection routes, 
      string name, string url, object defaults, object constraints) 
      where THandler : IHttpHandler, new() { 
    var route = new Route(url, new HttpHandlerRouteHandler<THandler>());
    route.Defaults = new RouteValueDictionary(defaults);
    route.Constraints = new RouteValueDictionary(constraints);
    routes.Add(name, route);
  }
}

This now allows me to register a route which is handled by an IHttpHandler very easily. In this case, I’m registering a route that will use my SimpleHttpHandler to handle any two segment URL.

public static void RegisterRoutes(RouteCollection routes) {
    routes.MapHttpHandler<SampleHttpHandler>("{foo}/{bar}");
}

And here’s the code for SampleHttpHandler for completeness. All it does is print out the route values.

public class SampleHttpHandler : IHttpHandler {
  public bool IsReusable {
    get { return false; }
  }

  public void ProcessRequest(HttpContext context) {
    var routeValues = context.Request.RequestContext.RouteData.Values;
    string message = "I saw foo='{0}' and bar='{1}'";
    message = string.Format(message, routeValues["foo"], routeValues["bar"]);

    context.Response.Write(message);
  }
}

When I make a request for /testing/yo I’ll see the message

I saw foo=’testing’ and bar=’yo’

in my browser. Very cool.

Limitation

One limitation here is that my http handler has to have a parameterless constructor. That’s not really that bad of a limitation since to register an HTTP Handler in the old way you had to make sure that the handler had an empty constructor.

However, this code that I wrote for this blog post is based on code that I added to Subtext. In that code, I am passing an IKernel (I’m using Ninject) to my HttpRouteHandler. That way, my route handler will use Ninject to instantiate the http handler and thus my http handlers aren’t required to have a parameterless constructor.

Try it out!

The RouteMagic solution includes a sample project that demonstrates all this.

Found a typo or error? Suggest an edit! If accepted, your contribution is listed automatically here.

Comments

avatar

18 responses

  1. Avatar for Jared Roberts
    Jared Roberts November 4th, 2009

    Two post in as many days! Yea @haacked!

  2. Avatar for Haacked
    Haacked November 4th, 2009

    @Jared ha! :) I'm on fire!

  3. Avatar for PK
    PK November 4th, 2009

    Hi Phil,
    I'm really really really embarassed to admit this ... but I'm not sure I can see _why_ we would want this?
    Yes, yes .. download the code, open it up and read it, etc.... but maybe some sample idea's why we would want to have a custom RouteHandler? Could this be
    a) Rss feeds (what about the built in REST stuff, into MVC2.0? format=xml/js, etc?)
    b) Image handler?
    ?
    Sorry for such a really noob question. Having a blond moment here *blush*

  4. Avatar for Craig Stuntz
    Craig Stuntz November 4th, 2009

    PK: It might have been a bit clearer if Phil had written, "What I this person really wants is a new *route* handler specifically for http handlers." In other words, you want to define a route which does something other than fire off an action. It lets you use routing rather than web.config to configure handlers. The idea is that you shouldn't need to write a new route handler if you already have an http handler, of which there are a lot.

  5. Avatar for Haacked
    Haacked November 4th, 2009

    Craig hits it on the nail. It's a nice way to register HTTP Handlers with more control over registration than you get with web.config.
    Now why would you use an HTTP Handler over simply using an MVC controller? If I was starting an app from scratch, I probably wouldn't. I'd probably just use controllers instead of handlers.
    But if I'm updating an existing app, or I have an existing http handler, this route handler could come in handy.

  6. Avatar for Andrei Rinea
    Andrei Rinea November 4th, 2009

    Thanks Craig for completing the post :)

  7. Avatar for PK
    PK November 5th, 2009

    Thanks guys for the follow up comments, also :) That cleared things up :) Cheers!!

  8. Avatar for Henry Wu
    Henry Wu April 16th, 2010

    Hi, I get 404 on the link for the sample code.
    Thanks!

  9. Avatar for Zac Avery
    Zac Avery April 18th, 2010

    I had been using a ASPX page with no content just to send some basic output to the response stream (for a simple variables within CSS files parser system that used the MapPageRoute method) but now I have this streaming the output directly. This is so much cleaner and seems to be miles faster. I would have never thought of this solution - thank you!

  10. Avatar for Milky Joe
    Milky Joe June 29th, 2010

    The sample code link is broken. Any chance of re-upping this?

  11. Avatar for 404
    404 January 30th, 2011

    404!!!!! On the SAMPLE CODE.
    Not cool.

  12. Avatar for haacked
    haacked January 30th, 2011

    Source code is now on CodePlex. See my blog post about my new Route Magic library.

  13. Avatar for AlexCode
    AlexCode October 20th, 2011

    I just wrote an extension method that makes this much more easily.
    You can call it like the following:

    // using the handler url
    routes.MapHttpHandlerRoute("MyControllerName", "Controllers/MyController", "~/mycontroller.ashx");

    // using an instance of the handler
    routes.MapHttpHandlerRoute("MyControllerName", "Controllers/MyController", new mycontroller());

    Have a look on my blog for the source code: HERE

  14. Avatar for syntax
    syntax January 30th, 2012

    What i dont get is how the instance of the IHttpHandler can be reused (when IsReuseable returns true), when it is created for each request, by the IRouteHandler?

  15. Avatar for steve
    steve February 27th, 2012

    Link to sample is still down.
    Sorry, that page you requested cannot be found. If the page does not show up within 24 hours, you can file a missing page report.
    Looking to the thread and all the previous notifications pertaining ot the issue it becomes clear this 24hour deal is just linkbait hoping we'll check back.

  16. Avatar for haacked
    haacked March 11th, 2012

    Hi Steve, I updated the post. The sample project is part of the RouteMagic repository on GitHub.

  17. Avatar for Vitaly
    Vitaly October 1st, 2012

    What about this alternative I wrote? - www.codeproject.com/...
    ...just a different approach, if one wants utmost flexibility ;)

  18. Avatar for Jone Polvora
    Jone Polvora August 1st, 2014

    If you are writing some framework and you want to register some custom IHttpHandlers without touching web.config, this is the best approach: Register an IHttpHandler through a route in some startup code of your framework. Very useful.