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:
- A browser (or some other client) issues an HTTP request to your application
- Your application performs some processing based on the incoming request
- 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:
- 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
- Action filters are executed both before and after the action method is executed. (implements
- Once the action method returns a result it is executed. A Result filter can run code both before and after this happens (implements
- If something goes wrong at any time during the process any Exception filters will be run (implements
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 (
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:
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:
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.MinValueand 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
GlobalActionFilterProvider– provides filters in the Global scope and again derives the order from the filter you provide (which defaults to –1). Unlike the
FilterAttribute.Orderproperty 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.
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.
No new comments are allowed on this post.