In ASP.NET MVC, Filters are used to inject logic at different levels of request processing and allow us to share logics across Controllers. For example, let’s say we want to run a security logic or a logging logic across the controller. To do so, we’ll write a filter containing those logics and enable them across all controllers. When we enable a filter across all controllers or actions, the filter enables the upcoming HTTP request.
Let us consider a scenario of Logging: for every incoming request, we need to log some data to the files on the basis of some logic. If we don’t create this logic inside a custom filter, then we will have to write logic for each controller’s action. This mechanism will lead to two problems:
- duplication of code; and
- violation of the Single Responsibility Principles; actions will now perform additional tasks of logging.
We can mitigate the problems above by putting the logging logics inside a custom action filter and applying the filter at all the controllers’ level.
Have you ever come across source code as shown in the image below? [Authorize] is an Authorization filter, and it gets executed before any HTPP request or Action method execution. The Authorize filter is part of MVC, but if needed, we can create a custom filter too.
In ASP.NET MVC, there are four types of filters:
- Authentication Filter
- Authorization Filter
- Action Filter
- Result Filter
- Exception Filter
The sequence of running of various filters are as follows:
- The Authentication filter runs before any other filter or action method
- The Authorization filter runs after the Authentication filter and before any other filter or action method
- The Action filter runs before and after any action method
- The Result filter runs before and after execution of any action result
- The Exception filter runs only if action methods, filters or action results throw an exception
In a diagram, we can depict the sequence of filter execution as shown below:
Each filter has its own purposes, however most of the time you will find yourself writing a Custom Action Filter. They get executed before and after execution of an action.
Custom Action Filter
We write custom action filters for various reasons. We may have a custom action filter for logging, or for saving data to database before any action execution. We could also have one for fetching data from the database and setting it as the global values of the application. We can create custom action filters for various reasons including but not limited to:
- Creating a privileged authorization
- Logging the user request
- Pre-processing image upload
- Fetching data to display in the layout menu
- Localization of the application
- Reading browser user agent information to perform a particular task
- Caching, etc.
To create a custom action filter, we need to perform the following tasks:
- Create a class
- Inherit it from ActionFilterAttribute class
- Override at least one of the following methods:
- OnActionExecuting– This method is called before a controller action is executed.
- OnActionExecuted– This method is called after a controller action is executed.
- OnResultExecuting– This method is called before a controller action result is executed.
- OnResultExecuted– This method is called after a controller action result is executed.
Let us create a custom action filter which will perform two tasks, in the most simplistic way. Of course you can write more sophisticated code inside the custom action filter, but we are going to create a custom filter with the name MyFirstCustomFilter, which will perform the following two tasks:
- Set some data value in global ViewBag.
- Log the incoming request to the controller action method.
The filter can be created as shown in the listing below:
usingSystem;usingSystem.Diagnostics;usingSystem.Web.Mvc;namespaceWebApplication1 {publicclassMyFirstCustomFilter : ActionFilterAttribute {publicoverridevoidOnResultExecuting(ResultExecutingContext filterContext) {//You may fetch data from database here filterContext.Controller.ViewBag.GreetMesssage = "Hello Foo";base.OnResultExecuting(filterContext); }publicoverridevoidOnActionExecuting(ActionExecutingContext filterContext) {var controllerName = filterContext.RouteData.Values["controller"];var actionName = filterContext.RouteData.Values["action"];var message = String.Format("{0} controller:{1} action:{2}", "onactionexecuting", controllerName, actionName); Debug.WriteLine(message, "Action Filter Log");base.OnActionExecuting(filterContext); } } }
In the above listing, we are simply setting ViewBag property for the controllers being executed. The ViewBag property will be set before a controller action result is executed, since we are overriding the OnResultExecuting method. Also, we are overriding OnActionExecuting to log the information about controller’s action method.
So now we’ve created the custom action filter. Now we can apply that at three possible levels:
- As a Global filter
- At a Controller level
- At an Action level
Applying as a Global Filter
We can apply a custom filter at a global level by adding a filter to the global filter in App_Start\FilterConfig. Once added at the global level, the filter would be available for all the controllers in the MVC application.
publicclassFilterConfig {publicstaticvoidRegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErrorAttribute()); filters.Add(new MyFirstCustomFilter()); } }
Filter at a Controller level
To apply a filter at the controller level, we can apply it as an attribute to a particular controller. When applied as controller level, the action would be available to all the actions of the particular controller. We can apply MyFirstCustomFilter to HomeController as shown in the listing below:
[MyFirstCustomFilter]publicclassHomeController : Controller {public ActionResult Index() {returnView(); } }
Filter at an Action level
Finally, to apply a filter at a particular action, we can apply it as an attribute of the Action as shown in the listing below:
[MyFirstCustomFilter]public ActionResult Contact() { ViewBag.Message = "Your contact page.";returnView(); }
And that’s about it for custom action filters! I hope you find this post useful, and thanks for reading. Have something to add? Feel free to leave a comment!