November 2010

Volume 25 Number 11

Cutting Edge - Dynamic Action Filters in ASP.NET MVC

By Dino Esposito | November 2010

Dino EspositoLast month I discussed the role and implementation of action filters in an ASP.NET MVC application. To review a bit: Action filters are attributes you use to decorate controller methods and classes with the purpose of having them perform some optional actions. As an example, you could write a Compress attribute and have it transparently filter any response generated by the method through a compressed gzip stream. The major benefit is that the compression code remains isolated in a distinct and easily reusable class, which contributes to keeping the responsibilities of the method as low as possible.

Attributes, however, are a static thing. To enjoy the benefits of their inherent flexibility, you need to go through an additional compile step. Changing the additional aspects of your controller class is easy, but it comes at the cost of modifying the source code. Generally speaking, this is not a big drawback. Most of the code maintenance work passes through physical changes made to the source code. The more you can make these changes effectively and with no risk of introducing regression, the better.

For Web sites (mostly Web portals) with highly volatile content and features, and for highly customizable software as a service (SaaS) applications, any solution that saves you from touching the source code is more than welcome. So the question is, is there anything you can do to load action filters dynamically? As the rest of this article demonstrates, the answer is a resounding yes.

Inside ASP.NET MVC

The ASP.NET MVC framework exposes a number of interfaces and overridable methods that you can customize nearly every aspect of. In brief, the entire collection of action filters for a controller method is loaded and kept in an in-memory list. As a developer, you’re allowed to access and inspect this list. With some more work, you can modify the list of action filters and even populate it dynamically.

Let’s take a closer look at how this works with an overview of the steps performed by the framework to perform an action. Along the way, you’ll meet the central component whose manipulation allows for dynamic filters: the action invoker.

The action invoker is ultimately responsible for the execution of any action methods on a controller class. The action invoker implements the internal lifecycle of each ASP.NET MVC request. The invoker is an instance of a class that implements the IActionInvoker interface. Each controller class has its own invoker object exposed to the world through a plain get/set property named ActionInvoker. The property is defined on the base System.Web.Mvc.Controller type as follows:

public IActionInvoker ActionInvoker {
  get {
    if (this._actionInvoker == null) {
      this._actionInvoker = this.CreateActionInvoker();
    }
    return this._actionInvoker;
  }
  set {
    this._actionInvoker = value;
  }
}

The CreateActionInvoker method is a protected overridable method of the Controller type. Here’s its implementation:

protected virtual IActionInvoker CreateActionInvoker() {
  // Creates an instance of the built-in invoker
  return new ControllerActionInvoker();
}

It turns out that the action invoker can be changed at will for any controller. However, because the invoker is involved at quite an early stage of the request lifecycle, you probably need a controller factory to exchange your own invoker for the default invoker. 
Coupled with an Inversion of Control (IoC) framework like Unity, this approach would let you change the invoker logic directly from the (offline) settings of the IoC container.

As an alternative, you can define a custom controller base class for your own application and override the CreateActionInvoker method to make it return just the invoker object you need. This is the approach that the ASP.NET MVC framework employs to support the asynchronous execution of controller actions.

The action invoker is built around the IActionInvoker interface, which is fairly simple as it exposes just one method:

public interface IActionInvoker {
  bool InvokeAction(
    ControllerContext controllerContext, 
    String actionName);
}

Keeping an eye on the default action invoker, let’s review the main tasks for which an action invoker is responsible. The invoker first gets information about the controller behind the request and the specific action to perform. Information comes through an ad hoc descriptor object. The descriptor includes the name and type of the controller, plus the list of attributes and actions. For performance reasons, the invoker builds its own cache of action and controller descriptors.

It’s interesting to take a quick look at the prototype of the ControllerDescriptor class in Figure 1. The class represents just the base class for any real descriptor.

Figure 1 The ControllerDescriptor Class

public abstract class ControllerDescriptor : 
  ICustomAttributeProvider {
  // Properties
  public virtual string ControllerName { get; }
  public abstract Type ControllerType { get; }
  // Method
  public abstract ActionDescriptor[] GetCanonicalActions();
  public virtual object[] GetCustomAttributes(bool inherit);
  public abstract ActionDescriptor FindAction(
    ControllerContext controllerContext, 
    string actionName);
  public virtual object[] GetCustomAttributes(
    Type attributeType, bool inherit);
  public virtual bool IsDefined(
    Type attributeType, bool inherit);
}

The ASP.NET MVC framework employs two concrete descriptor classes that heavily use the Microsoft .NET Framework reflection internally. One is named ReflectedControllerDescriptor; the other is only used for asynchronous controllers and is named ReflectedAsyncControllerDescriptor.

I can hardly think of a realistic scenario where you might need to create your own descriptor. However, for those who are curious, let’s take a look at how it’s done.

Imagine you create a derived descriptor class and override the method GetCanonicalActions to read the list of supported actions from a configuration file or a database table. In this way, you can remove valid action methods from the list based on some configurable content. To make this work, however, you need to bring in your own action invoker and write its GetControllerDescriptor method accordingly to return an instance of your custom descriptor:

protected virtual ControllerDescriptor 
  GetControllerDescriptor(
  ControllerContext controllerContext);

Getting information about the controller and action method is only the first step accomplished by the action invoker. Next, and more interestingly for the purposes of this article, the action invoker gets the list of action filters for the method being processed. In addition, the action invoker checks the authorization permissions of the user, validates the request against potentially dangerous posted data and then invokes the method.

Getting the List of Action Filters

Even though the action invoker is identified with the IActionInvoker interface, the ASP.NET MVC framework uses the services of the built-in class ControllerActionInvoker. This class supports a lot of additional methods and features, including the aforementioned descriptors and action filters.

The ControllerActionInvoker class offers two main points of intervention for manipulating action filters. One is the GetFilters method:

protected virtual ActionExecutedContext 
  InvokeActionMethodWithFilters(
  ControllerContext controllerContext, 
  IList<IActionFilter> filters, 
  ActionDescriptor actionDescriptor, 
  IDictionary<string, object> parameters);

The other is the InvokeActionMethodWithFilters method:

protected virtual FilterInfo GetFilters(
  ControllerContext controllerContext, 
  ActionDescriptor actionDescriptor)

Both methods are marked protected and virtual, as you can see.

The invoker calls GetFilters when it needs to access the list of filters defined for a given action. As you may guess, this occurs quite early in the lifecycle of a request and earlier than any invocation of the method InvokeActionMethodWithFilters.

You should note that after calling GetFilters, the invoker holds available the entire list of filters for each possible category, including exception filters, result filters, authorization filters and, of course, action filters. Consider the following controller class:

[HandleError]
public class HomeController : Controller {
  public ActionResult About() {
    return View();
  }
}

The entire class is decorated with the HandleError attribute, which is an exception filter, and no other attribute is visible.

Now let’s add a custom invoker, override the method GetFilters and place a breakpoint on the final line of the code, like so:

protected override FilterInfo GetFilters(
  ControllerContext controllerContext, 
  ActionDescriptor actionDescriptor) {
  var filters = base.GetFilters(
    controllerContext, actionDescriptor);
  return filters;
}

Figure 2 shows the actual content of the variable filters.

image: Intercepting the Content of the Filters Collection

Figure 2 Intercepting the Content of the Filters Collection

The FilterInfo class—a public class in System.Web.Mvc—offers specific collections of filters for each category:

public class FilterInfo {
  public IList<IActionFilter> ActionFilters { get; }
  public IList<IAuthorizationFilter> AuthorizationFilters { get; }
  public IList<IExceptionFilter> ExceptionFilters { get; }
  public IList<IResultFilter> ResultFilters { get; }
  ...
}

As in Figure 2, for the trivial class shown earlier you count one action filter, one authorization filter, one result filter and two exception filters. Who defined the action, result and authorization filters? The controller class itself is an action filter. In fact, the base Controller class implements all related filter interfaces:

public abstract class Controller : 
    ControllerBase, IDisposable,
    IActionFilter, IAuthorizationFilter, 
    IExceptionFilter, IResultFilter {
    ...
  }

The base implementation of GetFilters reflects attributes from the controller class using reflection in the .NET Framework. In your implementation of the method GetFilters, you can add as many filters as you want, reading them from any sort of location. All you need is a piece of code such as this:

protected override FilterInfo GetFilters(
  ControllerContext controllerContext, 
  ActionDescriptor actionDescriptor) {
  var filters = base.GetFilters(
    controllerContext, actionDescriptor);
  // Load additional filters
  var extraFilters = ReadFiltersFromConfig();
  filters.Add(extraFilters);
  return filters;
}

This approach gives you the greatest flexibility and works for any goal you want to achieve or with whatever type of filter you want to add.

Invoking an Action

InvokeActionMethodWithFilters is invoked during the process that takes the performance of the action method. In this case, the method receives the list of action filters to take into account. However, you’re still allowed to add extra filters at this time. Figure 3 shows a sample implementation of InvokeActionMethodWithFilters that dynamically adds an action filter for compressing the output. The code in Figure 3 first checks whether the method being invoked is a particular one and then it instantiates and adds a new filter. It goes without saying that you can determine the filters to load in any way that suits you, including reading from a configuration file, a database or whatever else. When overriding the InvokeActionMethodWithFilters method, all you do is check the method being executed, attach additional action filters and invoke the base method so that the invoker can proceed as usual. To retrieve information about the method being executed, you resort to the controller context and the action descriptor.

Figure 3 Adding an Action Filter Before Executing the Action

protected override ActionExecutedContext 
  InvokeActionMethodWithFilters(
  ControllerContext controllerContext, 
  IList<IActionFilter> filters, 
  ActionDescriptor actionDescriptor, 
  IDictionary<String, Object> parameters) {
  if (
    actionDescriptor.ControllerDescriptor.ControllerName == "Home" 
    && actionDescriptor.ActionName == "About") {
    var compressFilter = new CompressAttribute();
    filters.Add(compressFilter);
  }
  return base.InvokeActionMethodWithFilters(
    controllerContext, 
    filters, actionDescriptor, parameters);
}

So you have two possible approaches to add filters dynamically to a controller instance: overriding GetFilters and overriding InvokeActionMethodWithFilters. But, is there any difference?

The Action Lifecycle

Going through GetFilters or InvokeActionMethodWithFilters is pretty much the same thing. Some differences do exist, even though it’s no big deal. To understand the difference, let’s find out more about the steps taken by the default action invoker when it comes to executing an action method. Figure 4 summarizes the lifecycle.

image: The Lifecycle of an Action Method

Figure 4 The Lifecycle of an Action Method

After getting descriptors, the invoker gets the list of filters and enters into the authorization phase. At this time, the invoker deals with any authorization filters you may have registered. If the authorization fails, any action result is executed completely ignoring any filters.

Next, the invoker checks whether the request requires validation of posted data and then moves on to executing the action method loading all currently registered filters.

In the end, if you intend to dynamically add any authorization filters, then it will only work if you do it through the GetFilters method. If your goal is only adding action filters, result filters or exception filters, then using either method just produces the same result.

Dynamic Filters

Dynamic loading of filters is an optional feature that mostly serves the purpose of applications with an extremely high-level feature volatility. A filter, specifically an action filter, enables aspect-oriented capabilities in an ASP.NET MVC controller class as it lets developers turn on and off behavior in a declarative manner.

When you write the source code of a controller class, you can choose to add action attributes to the class or the method level. When you read about action filters from an external data source, how to organize information so that it’s clear which filters apply to which methods may not be obvious. In a database scenario, you can create a table where you use method and controller name as the key. In a configuration scenario, you probably need to work out a custom configuration section that delivers just the information you need. In any case, the ASP.NET MVC framework is flexible enough to let you decide which filters are to be applied on a per-method and even on a per-call basis.


Dino Esposito  is the author of “Programming ASP.NET MVC” from Microsoft Press (2010). Based in Italy, Esposito  is a frequent speaker at industry events worldwide.

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