October 2010

Volume 25 Number 10

Cutting Edge - Action Filters in ASP.NET MVC

By Dino Esposito | October 2010

The biggest challenge many software architects face today is how to design and implement an application that can meet all version 1 requirements plus all others that can show up afterward. Maintainability has been one of the fundamental attributes of software design since the first draft of the ISO/IEC 9126 paper, back in 1991. (The paper provides a formal description of software quality and breaks it down into a set of characteristics and sub-characteristics, one of which is maintainability. A PDF version of the paper can be obtained at iso.org.)

The ability to serve a customer’s present and future needs certainly isn’t a new requirement for any piece of software. However, what many Web applications require today is a subtle and short-term form of maintainability. Many times customers don’t want new functions or a different implementation of an existing feature. They just want you to add, replace, configure or remove small pieces of functionality. A typical example is when Web sites with large audiences launch specific advertising campaigns. The overall behavior of the site doesn’t change, but extra actions must be performed along with existing actions. Moreover, these changes usually aren’t persistent. They must be removed after a few weeks to then be reincorporated a few months later, be configured differently and so forth. You need the ability to program any required functionality by composing small pieces together; you need to track dependencies without greatly impacting the source code; and you need to move toward an aspect-oriented design of software. These are some of the primary reasons behind the rapid adoption of Inversion of Control (IoC) frameworks in many enterprise projects.

So what’s this article all about? It isn’t meant to be a boring lecture on how software is changing today. Instead, it’s an in-depth exploration of a powerful feature of ASP.NET MVC controllers that can notably help you in the building of aspect-oriented Web solutions: ASP.NET MVC action filters.

What’s an Action Filter, Anyway?

An action filter is an attribute that, when attached to a controller class or a controller method, provides a declarative means to attach some behavior to a requested action. By writing an action filter, you can hook up the execution pipeline of an action method and adapt it to your needs. In this way, you can also take out of the controller class any logic that doesn’t strictly belong to the controller. In doing so, you make this particular behavior reusable and, more importantly, optional. Action filters are ideal for implementing crosscutting concerns that affect the life of your controllers.

ASP.NET MVC comes with a few predefined action filters such as HandleError, Authorize and OutputCache. You use HandleError to trap exceptions thrown during the execution of methods on the target controller class. The programming interface of the HandleError attribute lets you indicate the error view to associate with a given exception type.

The Authorize attribute blocks the execution of a method for unauthorized users. It doesn’t distinguish, however, between users who just haven’t logged in yet and logged users lacking enough permissions to perform a given action. In the configuration of the attribute, you can specify any roles required to execute a given action.

The OutputCache attribute caches the response of the controller’s method for the specified duration and requested list of parameters.

An action filter class implements several interfaces. The full list of interfaces is presented in Figure 1.

Figure 1 Interfaces for an Action Filter

Filter Interfaces Description
IActionFilter Methods in the interface are invoked before and after the execution of the controller method.
IAuthorizationFilter Methods in the interface are invoked before the controller method executes.
IExceptionFilter Methods in the interface are invoked whenever an exception is thrown during the execution of the controller method.
IResultFilter Methods in the interface are invoked before and after the processing of the action result.

In the most common scenarios, you’re mostly concerned with IActionFilter and IResultFilter. Let’s get to know them more closely. Here’s the definition of the IActionFilter interface:

public interface IActionFilter
{
  void OnActionExecuted(ActionExecutedContext filterContext);
  void OnActionExecuting(ActionExecutingContext filterContext);
}

You implement the OnActionExecuting method to execute code before the controller’s action executes; you implement OnActionExecuted to post-process the controller state a method has determined. The context objects provide a lot of runtime information. Here’s the signature of ActionExecutingContext:

public class ActionExecutingContext : ControllerContext
{
  public ActionDescriptor ActionDescriptor { get; set; }
  public ActionResult Result { get; set; }
  public IDictionary<string, object> ActionParameters { get; set; }
}

The action descriptor, in particular, provides information about the action method, such as its name, controller, parameters, attributes and additional filters. The signature of ActionExecutedContext is only a bit different, as shown here:

public class ActionExecutedContext : ControllerContext
{
  public ActionDescriptor ActionDescriptor { get; set; }
  public ActionResult Result { get; set; }
  public bool Canceled { get; set; }
  public Exception Exception { get; set; }
  public bool ExceptionHandled { get; set; }
}

In addition to a reference to the action description and action result, the class supplies information about an exception that could’ve occurred and offers two Boolean flags that deserve more attention. The ExceptionHandled flag indicates that your action filter is given a chance to mark an occurred exception as handled. The Canceled flag concerns the Result property of the ActionExecutingContext class.

Note that the Result property on the ActionExecutingContext class exists only to move the burden of generating any action response from the controller method to the list of registered action filters. If any action filters assign a value to the Result property, the target method on the controller class will never be invoked. In doing this, you bypass the target method, moving the burden of producing a response entirely to action filters. However, if multiple action filters were registered for a controller method, then they’d share the action result. When a filter sets the action result, all subsequent filters in the chain will receive the ActionExecuteContext object with the property Canceled set to true. Whether you set Canceled programmatically in the action-executed step, or set the Result property in the action-executing step, the target method will never be run.

Writing Action Filters

As mentioned, when it comes to writing custom filters, most of the time you’re interested in filters that pre- and post-process the action result and filters that run before and after the execution of the regular controller method. Instead of implementing interfaces natively, an action filter class is commonly derived from ActionFilterAttribute:

public abstract class ActionFilterAttribute : FilterAttribute, IActionFilter, IResultFilter
{
  public virtual void OnActionExecuted(ActionExecutedContext filterContext);
  public virtual void OnActionExecuting(ActionExecutingContext filterContext);
  public virtual void OnResultExecuted(ResultExecutedContext filterContext);
  public virtual void OnResultExecuting(ResultExecutingContext filterContext);
}

You override OnActionExecuted to add some custom code to the execution of the method. You override OnActionExecuting as a precondition to the execution of the target method. Finally, you override OnResultExecuting and OnResultExecuted to place your code around the internal step that governs the generation of the method response.

Figure 2shows a sample action filter that adds compression programmatically to the response of the method it’s applied to.

Figure 2 A Sample Action Filter for Compressing the Method Response

public class CompressAttribute : ActionFilterAttribute
{
  public override void OnActionExecuting(
    ActionExecutingContext filterContext)
  {
    // Analyze the list of acceptable encodings
    var preferred = GetPreferredEncoding(
      filterContext.HttpContext.Request);
    // Compress the response accordingly
    var response = filterContext.HttpContext.Response;
    response.AppendHeader("Content-encoding", preferred.ToString());
    if (preferredEncoding == CompressionScheme.Gzip)
    {
      response.Filter = new GZipStream(
        response.Filter, CompressionMode.Compress);
    }
    if (preferredEncoding == CompressionScheme.Deflate)
    {
      response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress);
    }
    return;
  }
  static CompressionScheme GetPreferredEncoding(HttpRequestBase request)
  {
    var acceptableEncoding = request.Headers["Accept-Encoding"];
    acceptableEncoding = SortEncodings(acceptableEncoding);

    // Get the preferred encoding format 
    if (acceptableEncoding.Contains("gzip"))
      return CompressionScheme.Gzip;
    if (acceptableEncoding.Contains("deflate"))
      return CompressionScheme.Deflate;
    return CompressionScheme.Identity;
  }
  static String SortEncodings(string header)
  {
    // Omitted for brevity
  }
}

In ASP.NET, compression is commonly achieved by registering an HTTP module that intercepts any requests and compresses their responses. In the alternative, you can also enable compression at the IIS level. ASP.NET MVC supports both scenarios well and also offers a third option: controlling compression on a per-method basis. In this way, you can control the level of compression for a specific URL without the need of writing, registering and maintaining an HTTP module.

As you can see in Figure 2, the action filter overrides the OnActionExecuting method. This may sound a bit weird at first, as you might expect compression to be a crosscutting concern you take care of just before returning some response. Compression is implemented through the Filter property of the intrinsic HttpResponse. Any response being worked out by the runtime environment is returned to the client browser through the HttpResponse object. Subsequently, any custom streams mounted on the default output stream through the Filter property can alter the output being sent. Thus, in the course of the OnActionExecuting method, you just set up additional streams on top of the default output stream.

When it comes to HTTP compression, however, the most difficult part is taking into careful account the preferences of the browser. The browser sends its compression preferences through the Accept-Encoding header. The content of the header indicates that the browser is able to handle only certain encodings—usually gzip and deflate. To be a good citizen, your action filter must try to figure out exactly what the browser can handle. This can be a tricky task. The role of the Accept-Encoding header is fully explained in RFC 2616 (see w3.org/Protocols/rfc2616/rfc2616-sec14.html). In brief, the content of the Accept-Encoding header can contain a q parameter that’s meant to assign a priority to an acceptable value. For example, consider that all the following strings are acceptable values for an encoding, but even though gzip is apparently the first choice in all of them, only in the first one is it the favorite choice:

gzip, deflate
gzip;q=.7,deflate
gzip;q=.5,deflate;q=.5,identity

A compression filter should take this into account, like the filter in Figure 2 does. These details should reinforce the idea that when you write an action filter, you’re interfering with the handling of the request. Subsequently, anything you do should be consistent with the expectation of the client browser.

Applying an Action Filter

As mentioned, an action filter is just an attribute that can be applied to individual methods as well as to the whole parent class. Here’s how you would set it up:

[Compress]
public ActionResult List()
{
  // Some code here
  ...
}

If the attribute class contains some public properties, you can assign values to them declaratively using the familiar notation of attributes:

[Compress(Level=1)]
public ActionResult List()
{
  ...
}

Figure 3 shows the compressed response as reported by Firebug.

image: A Compressed Response Obtained via the Compress Attribute

Figure 3 A Compressed Response Obtained via the Compress Attribute

An attribute is still a static way of configuring a method. This means that you need a second compile step to apply further changes. However, action filters expressed in the form of attributes provide a key benefit: They keep crosscutting concerns out of the core action method.

A Broader Look at Action Filters

To measure the real power of action filters, think of applications that need a lot of customization work over time and applications that require adaptation when installed for different customers.

Imagine, for example, a Web site that at some point launches an advertising campaign based on reward points a registered user may gain if he performs some standard action within a site (buying goods, answering questions, chatting, blogging and so on). As a developer, you probably need some code that runs after the regular method of executing a transaction, posting a comment or starting a chat has run. Unfortunately, this code is come-and-go and should hardly be part of the original implementation of the core action method. With action filters, you can create distinct components for each required scenario and, for example, arrange an action filter for adding reward points. Next, you attach the reward filter to any methods where the post action is required; then you recompile and go.

[Reward(Points=100)]
public ActionResult Post(String post)
{
  // Core logic for posting to a blog
  ...
}

As mentioned, attributes are static and require an additional compile step. While this may not be desirable in all cases (say, in sites with highly volatile features), it’s much better than nothing. At the minimum, you gain the ability to update Web solutions quickly and with a low impact on existing features, which is always good to keep regression failures under strict control.

Dynamic Loading

This article demonstrated action filters in the context of controller action methods. I demonstrated the canonical approach of writing filters as attributes that you use to decorate action methods statically. There’s an underlying question, however: Can you load action filters dynamically?

The ASP.NET MVC framework is a well-written (and large) piece of code, so it exposes a number of interfaces and overridable methods with which you can customize nearly every aspect of it. Happily, this trend is going to be reinforced by the upcoming Model-View-Controller (MVC) 3. According to the public roadmap, one of the team’s objectives for MVC 3 is enabling dependency injection at all levels. The answer to the previous question about dynamic loading, therefore, lies in the dependency-injection abilities of the MVC framework. A possible winning strategy is customizing the action invoker to gain access to the list of filters before the execution of a method. Because the list of filters looks like a plain read/write collection object, it shouldn’t be that hard to populate it dynamically. But this is good fodder for a new column.


Dino Esposito is the author of “Programming ASP.NET MVC” from Microsoft Press (2010) and has coauthored “Microsoft .NET: Architecting Applications for the Enterprise” (Microsoft Press, 2008). Based in Italy, Esposito is a frequent speaker at industry events worldwide. You can join his blog at weblogs.asp.net/despos.

Thanks to the following technical expert for reviewing this article: Scott Hanselman