MVC3: Filters

In the last MVC post we looked at Filter Providers but didn’t really describe what filters were. Filters are special classes which can execute some functionality at certain points during each MVC request. Historically most filters have been attributes that you can apply to an action method or a controller class (not all as Controllers can also act as filters). Before talking about filters it’s worth looking at how a request in MVC is handled.

At the lowest level, all web applications behave the same way:

  1. A browser (or some other client) issues an HTTP request to your application
  2. Your application performs some processing based on the incoming request
  3. The application sends an HTTP response back to the client (this can be HTML, XML, JSon or even just a simple status code)

In an ASP.NET MVC application the incoming request is mapped to a method (called an Action) on a class (called the Controller). Once the controller has been created and the correct action method selected it is the job of the Action Invoker to run the method (action), retrieve its return value (result) and send something sensible back to the client. Along the way the action invoker allows filters to get involved at specific points in the process (and possibly alter it). There are 4 types of filter:

  1. Authorization filters are executed up front and may prevent the action method from being executed at all if they decide that the user is "not authorized" (implements IAuthorizationFilter)
  2. Action filters are executed both before and after the action method is executed. (implements IActionFilter)
  3. Once the action method returns a result it is executed. A Result filter can run code both before and after this happens (implements IResultFilter)
  4. If something goes wrong at any time during the process any Exception filters will be run (implements IExceptionFilter)

Filter class I’ll describe each of the filter types in future posts. Each filter is represented in MVC 3 as an object of the Filter class. This class contains 3 properties. The first (called Instance) holds an object that can implement any combination of the 4 filter interfaces defined above (it can even implement none of them but then your filter will never actually execute). The other two properties (Order and Scope) relate to the order in which filters are run.

Filters are run in a very specific order. Filters are sorted first by their ascending Order value. If two filters have the same Order value then they are sorted by their Scope value in the following order:

  1. First
  2. Global
  3. Controller
  4. Action
  5. Last

As an example here is the forwards order of a few filters:

  • Order = –1, Scope = First
  • Order = –1, Scope = Global
  • Order = –1, Scope = Last
  • Order = 0, Scope = Controller
  • Order = 0, Scope = Action
  • Order = 1, Scope = First

Note that Action Filters and Result Filters are actually run twice (once before and once after the thing they are filtering). When these filters are running before the action/result to which they apply they are run in forward order. When they are running after the action/result to which they apply they are run in the reverse order. You can think of it like this:

MVC3 Filters Order

The default filter providers will create filters with the following orders and scopes:

  • ControllerInstanceFilterProvider – Exposes the controller as a filter with an order of Int32.MinValue and a Scope of First. This means that the controller will always be the first filter
  • FilterAttributeFilterProvider – Finds filter attributes (inherits from FilterAttribute) on the controller and on the action method and exposes them using the Controller and Action scope accordingly. The Order value is derived from a property on the attribute itself (FilterAttribute.Order) and defaults to –1. In fact, if you try to set a filter attributes order to less than –1 it will throw an ArgumentOutOfRangeException
  • GlobalActionFilterProvider – provides filters in the Global scope and again derives the order from the filter you provide (which defaults to –1). Unlike the FilterAttribute.Order property you can set a value less than –1.

Finally, filters can specify whether or not they will allow multiple instances by setting the property IMvcFilter.AllowMutliple (filters derived from FilterAttribute will provide this value based on any supplied AttributeUsage attribute they have). If filters allow multiples then each instance of the filter that applies will be run for a given action/result. If a filter does not allow multiples then only one filter of the specified type will be executed. The one which is kept is the one with the highest Order and Scope (i.e the one which would normally be executed last).

Filters are a great feature of MVC that allow you to create a very orthogonal design for your application. Although the initial implementation of filters put a lot of code inside of attributes I don’t recommend doing that in MVC 3. Iinstead you should create marker attributes and use FilterProviders to apply your filter implementation classes where they’re needed. In the coming posts I’ll look at each of the different types of filters (Authorization, Action, Result and Exception) along with some examples of each from the MVC 3 framework. I’ll also discuss the circumstances under which you might like to create your own filters and how you’d go about doing so.

One last thing, there are a few attributes that ship in the framework and get applied to action methods but are not Filters. It’s easy to get these mixed up so I’ll list some here. AjaxOnlyAttribute, HttpPostAttribute, and NonActionAttribute are examples of Action Method Selectors and ActionNameAttribute is an Action Name Selector. Both of these types of attributes get involved in the MVC pipeline before the Action Invoker executes so they are not filters.

Posted by: Mike Minutillo
Last revised: 27 May, 2011 03:21 PM History

Comments

No comments yet. Be the first!

No new comments are allowed on this post.