Filters are attributes that you can add to the Controller or individual Actions in the controller. When added to the class, they affect every method in the class. When added to a specific method, only that Action will be affected.
The functionality associated with the action comes from implementing interfaces specific to the different types of filters.
- Authorization filters will implement the IAuthorizationFilter interface.
- Action filters will implement the IActionFilter interface.
- Result filters will implement the IResultFilter interface.
- Exception filters will implement the IExceptionFilter interface.
In addition to these interfaces, the framework includes a base class that implements the corresponding interface. When you define your own filter, you will generally start by deriving from this base class.
As you will see, this Filter model opens up many possibilities for adding common functionality.
Using Authorization Filters
Denise Adamson steps us through a battery of examples using the Authorize attribute. Along the way, we also get a peek at global filters which were introduced in MVC 3. We also get our first look at building a custom filter.
Doug steps through creating your own Authorize filter. Not only does he step you through what goes into the attribute itself, he also provides a great introduction and overview into how this attribute plays with others, including a sample of how to determine what other attributes have been applied.
Derick Bailey lays out the case for Activity Based authorization instead of Role Based checks. He makes some compelling points worth considering. The most compelling argument is the overhead in changing what roles are required to perform a specific activity. The activity associated with an action doesn’t change, but the roles associated with the activity may (and often do) change. Following a traditional approach, the roles required will be hardcoded in strings throughout your code. Another problem is that it is difficult to keep track of who can do what. Such documentation needs to be hand created by sifting through the code for the hard coded roles.
Unfortunately, this article lacks details on how to implement the system being described, but we can surmise what Derick may have had in mind.
His examples use an AuthorizeActivity attribute. This needs to take an activity name in the constructor. It will not necessarily be the same as the name of Action. This activity name will be used to retrieve a list or roles or users from a database and then matched against the authenticated user.The association between users, roles, and activities is centralized in the database. If there are any changes, you don’t have to modify code, retest it, redeploy, etc. Maintenance is simplified.
Using Exception Filters
Filters – Exception [Blog]
In this blog from Bubblog, we learn a few details about exception handling that may not be immediately obvious.
You can use the Order property of an Exception filter to control the order that your filters are applied. Go from specific to general. This is easily missed if you only focus on the OnException method.
Also note the sources for where the exception can occur:
- Another filter (authorization, action, or result filter)
- When the action method is executed
- When the action result is executed (The view logic)
Filters provide a much nicer mechanism for capturing exceptions raised in the view.
Herr DevHammer steps through not only the important task of wiring up the Exception filter but also defining and styling a View to show the relevant data. This key step is often over looked. While it is important to track your exceptions and log them, we also need to reassure users that their world is not ending. Let them know that something unexpected happened and what they should do next.
The display and format used in this blog is ideal for a development or QA environment, but you will need something a little bit more user friendly in production.
ASP.NET MVC Tutorial: Handling Errors and Exceptions [DevProConnections]
Dino Esposito takes you on a tour de force of exception handling in an MVC application. He covers how actions are invoked to discover how “unhandled exceptions” are handled.He steps you through how to swap out the view that you see when an error occurs. He shows how to setup custom routes for common HTTP exceptions. He also reiterates that even in the modern world of MVC, the classic Application_Error event handler is still relevant.
Exception Handling Best Practices
Even with all of the new bells and whistles, it is good to remember that some of the best practices are still best practices.
Exceptional Handling Best Practices in .NET [The Code Project]
Written 8 years ago, but still very relevant. Often when confronted with a list of best practices, you can take some of them with a hefty grain of salt. Many will not hold up to the test of time, and many others are only Best Practices in certain situations and actually frowned upon in others.
The long laundry list that Daniel put together is not like that. These best practices are still relevant and applicable. Make sure you have compelling reasons before casually ignoring them.
Using Action and Result Filters
In a general sense all of the filters that we have seen so far are Action Filters, but here we are going to turn our attention specifically to filters that wrap the action method execution, and filters that wrap the ActionResult object. As we have seen earlier, this is what the Exception filters do, but they are a special case.
It is a shame that the naming conventions here were not more explicit to better distinguish Action/Result filters from Action Filters.
Creating Custom Action Filters [MSDN Library]
Creating a custom action or result filter is relatively straightforward. Derive from ActionFilterAttribute and override the key methods that are relevant to what you want to do.
- OnActionExecuting gets called just before the action itself is called and receives an ActionExecutingContext object.
- OnActionExecuted gets called right after the action finishes and receives an ActionExecutedContext object.
- OnResultExecuting gets called just before the ActionResult is invoked and receives a ResultExecutingContext object.
- OnResultExecuted is called just after the ActionResult is executed and receives a ResultExecutedContext object.
The mechanics of implementing the filters are simple, what you can do is limited only by your imagination.
In this blog Andrew Woodcock wanted to be able to skip the checks if the model state was valid in his actions. This is repetitive boiler plate code and a good candidate for pulling up to a higher level of abstraction.
To make this work, he defined a new filter called OnlyProcessIfValidAttribute and overrode the OnActionExecuting method. Here he simply needs to check the ModelState. If it is valid, let it continue on executing the Action. If the ModelState is not valid, we want to cancel execution.
He cancels the Action by explicitly setting the Result property of the ActionExecutingContext. While this is an intriguing example, it only works when associated with Actions return JSON data. For other uses, you will need to change the value assigned to the filterContext.Result.
Determining what to assign to the filterContext.Result will be the most difficult piece for such an implementation.The OnActionExecuting method does not have a convenient method for cancelling processing because there is no obvious universally applicable answer for what the user should see if an Action is cancelled..
If you have been paying attention, you may have noticed that all of these overridden methods in the ActionFilter are also in the Controller base class, and they have the same meaning. This may cause some confusion over when should you use an ActionFilter and when should you use a Controller Base Class.
In this blog, K. Scott Allen steps you through some of the trade-offs between the two approaches. To muddy the waters a bit more, we now have global filters which gives you a third option. If you want to add a filter to EVERY action, you can simply:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
In this blog Murali Takalpati steps you through using a filter to add an item to the ViewBag. This opens up a world of possibilities. If your ViewModels implement a common interface and what you want add is in this interface, you can rewrite this as:
public void OnResultExecuting(ResultExecutingContext filterContext)
var model = filterContext.Controller.ViewData.Model as IUserModel;
if (model != null)
model.UserName = "tgmurali";
In this blog, Chase B Gale ties all of the pieces together to build an activity tracking system using only filters. He does a good job building up the various methods involved and explaining how the pieces fit together.The switch statement is useful here to keep the focus on the filters for this example. If you want to do something similar in your projects, you may want to have a more robust option instead of the switch statement used here. For Production code, you may want to use Attributes or Reflection instead of relying on a hard coded list of controller names.
We saw this with exception handling earlier that the order that the filters run matters. In the case of exceptions, we want it to go from most specific to most generic. This is controlled by setting the Order property when the attributes are added, but it can be used for so much more.
MVC3 Filter Ordering [Blog]
Raj Aththanayake goes through every possible filter / order combination and explores how the rules interact. As you can see, the rules potentially get to be quiet complicated. For most practical applications, you can keep it simple and not get bogged down in these details, but fortunately Raj took the time to wade through and document the various scenarios.
Since being able to add Filters to individual actions, individual controllers, and globally were not enough MVC 3 added the concept of Filter Providers to allow you even more control.
Exclude a Filter [Blog]
In this blog Ori steps through developing his ExcludeFilterAttribute. The intention is that you would add a Filter at the Controller level and have it apply to every Action in that control but add an ExcludeFilterAttribute to any action that did not need this Controller level attribute.
In addition to the ExcludeFilterAttribute, he also created a new FilterProvider called ExcludeFilterProvider. This provider will start with a list of all associated Filters and will then look for any ExcludeFilterAttributes. If any are found, the associated filters are removed from the list of associated attributes.
This is just the tip of possibilities with filter providers; you could define any number of conditional logic to determine when a Filter should be used
Additional Filter Examples
Kazi Manzur steps through defining a couple of attributes to implement Caching and Compression filters. In this case, the caching filter will add HTTP Headers to the response to define the caching policy. This allows the browser to manage and deal with the cache and the server will not even be involved.
The Compression filter works by detecting what the user agent can handle, and then add the appropriate HTTP headers to the response. These two filters can be easily combined to give you a nice reduction in bandwidth and take the load off of your server.