November 10, 2013

ASP.net MVC Handler and Filter

One problem for building domain driven products is knowing where to put your cross cutting concerns, properly. What works nice is .Net attributes for cross cutting concerns, like logging, error handling, and caching. This is done in ASP.net MVC through Handlers and Filters.

Handlers

So handlers are simple idea. They are the first step that gets executed, before ANYTHING else. Even before your controllers. It works like this, you add it to your WebApi.Config, as part of your route. Everything in that route uses the handlers that are created.

 public static class WebApiConfig { public static void Register(HttpConfiguration config) { config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", constraints: null, handler: new PrintHandler(){ InnerHandler = new HttpControllerDispatcher(config) }, defaults: new { id = RouteParameter.Optional } ); config.EnableQuerySupport(); // To disable tracing in your application, please comment out or remove the following line of code // For more information, refer to: http://www.asp.net/web-api TraceConfig.Register(config); } } 

The handler we added is PrintHandler. This is meant to print EVERY header to our debug console. But, mind you, you can add any logic into this handler, logging, error handling, caching and etc. When you do add a handler, it will be for EVERY request. So let’s check out the code for the PrintHandler.

 public class PrintHandler : DelegatingHandler { public PrintHandler(HttpConfiguration httpConfiguration) { InnerHandler = new HttpControllerDispatcher(httpConfiguration); } public PrintHandler(HttpMessageHandler handler) { InnerHandler = handler; } private static object locker = new object(); protected async override System.Threading.Tasks.Task SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) { Debug.WriteLine("Print Header: {0}", request.Headers); return base.SendAsync(request, cancellationToken); } } </pre> 

There are a few things to note. One, the constructors take 2 different objects, another handler and a controller dispatch. If you want to know more about this pattern, it’s called chain of responsibility. Basically, we need to tell what the next handlers we want to process, after the PrintHandler, or we can say to process the controller finally. While handlers are great for every request, sometimes you want to fine tune just a few controllers, vs ALL controllers for that route. Let’s take a look at filters.

Filters

If you are more of an aspect oriented programming guy, filters are your choice. To start off a new filter attribute, create a class that inherits from ActionFilterAttribute

 public class PrintAttribute : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext filterContext) { Debug.WriteLine("Executing this action: {0}", filterContext.ActionDescriptor.ActionName); base.OnActionExecuting(filterContext); } } 

What is going on is that you can get a few things about what the controller method that you are calling, like action name. You will also notice that this is on Executing, but there are other actions that you can implement for more information, like after executing. To use this, it is as easy as adding the attribute to the controller action you want to affect.

 public class HomeController : Controller { [Print] public ActionResult Index() { return View(); } } 

ASP.net MVC is doing a great job allowing everyone to extend their code using AOP and DDD techniques. This definitely gives us more ability to insert new functionality into the pipeline, before it gets to your business logic. It’s very important to know where you can add your code.