Monday, 28 May 2012

ASP.NET Web API Series - Part 7: Real world Message Handlers


Introduction

[Level T2] In the previous post we reviewed Web API's pipeline a.ka. Russian Doll model. In this post we further on what discussed with a few examples built by the community. Also before that, we look on how to use a per-route message handler while keeping all the goodness of controller functionality.

If you have written a real-world handler in ASP.NET Web API, please contact me in the comments below or on Twitter (@aliostad) to be reviewed and added to the post.

Have the cake and eat it at the same time

In the previous post, we talked about the benefits of the per-route message handlers. Henrik's example is an implementation of HttpMessageHandler which will basically needs to do every thing by itself. So the question arises, how can I have the flexibility of the per-route message handlers while benefit from all the luxury of formatting, action invocation, controller mechanisms, etc. In other words, how can I invoke my controller in a per-route case? Well that sounds like have the cake and eat it at the same time.


Well, it turns out it is possible. I managed to get this working, calling my actions using a per-route handler. The trick is that you set up your Russian dolls and last one ending with an HttpControllerDispatcher.

So let's look at an example. Here we have is a humble delegating handler that outputs the request URL to the trace.

public class TraceHandler: DelegatingHandler
{
 protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
 {
  Trace.WriteLine(request.RequestUri.ToString());
  return base.SendAsync(request, cancellationToken);
 }
}

Now if we want to set up this DelegatingHandler per-route, we simply create a new HttpControllerDispatcher and set it to the InnerHandler of the TraceHandler:

config.Routes.MapHttpRoute(
 "DefaultApi",
 "api/{controller}/{id}",
 new{ id = RouteParameter.Optional},
 null,
 new TraceHandler(){InnerHandler = new HttpControllerDispatcher(config)});

Creating HttpControllerDispatcher is easy and we just need to pass the HttpConfiguration object (depending on the SelfHost or Web scenario).

So this way we can have our per-route delegating handler running only for that route yet all the controller action binding and formatting intact.

Real-world message handlers

Since the beta version of the Web API was out, community has been building interesting and useful handlers. So I thought instead of me coming up with arbitrary or simple cases, I could introduce the great stuff community has done so far. And that is what I did. The very last one is the introduction of my CachingHandler which deserves a post on its own.

Tracking Web API usage by your customers

Filip Woj shows us how to build a DelegatingHandler to support tracking usage of your API. But not just that, actually all the nitty-gritty of building the infrastructure (repositories, etc) to support it. This can be a very useful feature if you want to monetise your API and need to charge per call or make sure the call is made within the number of calls allowed for the customer.

Radenko tries to solve a similar problem with throttling usage of the API. He uses HttpRuntime.Cache for storing the statistics. As he explains, he will be moving the storage to Membase. Generally use of the cache for storing data is not great since system can remove the data if memory becomes a scarce resource (which happens often on a web server, especially the one needing throttling).

Authentication and security

John Petersen looks into using a delegating handler for token-based authentication. He uses public/private key and RSA for creating tokens (perhaps we could also choose a stronger algorithm since token is small unlike the whole HTTP communication) and creates 3 different handlers: one to make sure the request uses TLS/SSL, other to ensure the IP address of the client is from a white-list and finally the handler to create and verify authentication token.

Antony Scott also takes on the Basic Authentication and explains how to process the authentication header and set the identity of the current thread. There is not a lot of code there, not more than you need displaying how easy it is to do basic authentication if you use all the correct points of the system.

Perhaps the most important implementation of security which also includes use of message handlers, is Dominick Baier's Thinktecture Identity model on github. Dominick explains this in his blog post here and his library supports all major standards.

Other

Mike Wasson explains here how to create HTTP method override delegate in ASP.NET Web API. The idea is that using HTTP methods other that POST and GET might be tricky on some servers. For example, there is a known issue in IIS whereby PUT or DELETE methods will return 404 if you have WebDAV installed on the server. In such cases, by convention client sends a custom HTTP header with the key of X-HTTP-Method-Override containing the alternate method. In this case, the handler will read the header and change the method. It is important to note that binding to the controller and action selection and invocation happens later so this change of method will be effective. 

Caching

HTTP caching is a very important feature in RFC 2616. A whole chapter in the spec is dedicated to it and arguably involves some of the most complex rules in the whole spec. Caching is also one of the tenants of REST and as such plays an important role in the design, architecture and scalability model of the web. In the last few weeks I have been busy building a CachingHandler for the WebApiContrib and currently it is available in my fork of the project. In the next post, I will be going through some of the challenges I was facing and the solutions I came up in writing this complex handler. It was good fun!

Conclusion

Per-route message handlers can be enhanced if we mix delegating handler(s) with HttpControllerDispatcher. In this case, we can have a number of delegating handlers last one ending with the controller dispatcher. This leaves media formatting, controller selection, model binding and action invocation intact while we can have all the flexibility of per-route handlers.

We also reviewed a few useful handlers built by the community and available at the time of writing this post. In the next post, we will cover the CachingHandler.

No comments:

Post a Comment