Built-In Filter Type In ASP.NET Core MVC

Introduction
 
The ASP.net core framework include five built-in filter type that we can sub-class and customize base on our requirement. The framework supports the following built-in filters type.
  • Authorization filters
  • Resource filters
  • Action filters
  • Exception filters
  • Result filters
Authorization filter
 
It controls access to the action method. It is the first filter to be executed within the filter pipeline. It supports only the before method (other filter type supports both before and after). We can write custom authorization filter to implement our own authorization framework. The built-in filter implementation is only responsible for calling the authorization mechanism.
 
Authorization in asp.net core MVC is controlled through "AuthorizeAttribute". By applying this attribute to the controller or any action method, we can limit access to the controller or action method to any authenticated user.
 
Example
  1. [Authorize]  
  2. [Route("Home/autho")]  
  3. public IActionResult Index7()  
  4. {  
  5.       return View("Index");  
  6. }  
 Output

 
 
We can also use "AllowAnonymousAttribute" attribute to allow access by non-authenticated users to action method.
  1. [Authorize]  
  2. public class HomeController : Controller  
  3. {  
  4.         [Route("Home/login")]  
  5.         [AllowAnonymous]  
  6.         public IActionResult Index8()  
  7.         {  
  8.               
  9.             return View("Index");  
  10.         }  
  11.   
  12.         [Route("Home/testmethod")]  
  13.         public IActionResult Index8()  
  14.         {  
  15.               
  16.             return View("Index");  
  17.         }  
  18. }  
In the above example, it would allow only authenticated users to access the HomeController except Index8 (Home/login) action method, that is accessible by every-one.
 
The AllowAnonymous attribute always bypasses all authorization statements. The Authorize attribute will always be ignored, if we use AllowAnonymous attribute in combination with Authorize attribute i.e. If we use AllowAnonymous at controller level and apply Authorize attribute on the same controller or any action method of this controller, it will be ignored.
 
Resource filters.
 
The Resource filters handle the request after authorization. It can run the code before and after the rest of the filter is executed. This executes before the model binding happens. It can be used to implement caching.
 
It supports both sync and async implementation. It implements either the IResourceFilter for sync or IAsyncResourceFilter async implementation. They are mainly useful if we want to short circuit most of the work a request is doing. For example "Caching" filter avoids the rest of the pipeline if response is already cached.
 
Example 
  1. namespace BuiltinFilters.Filters  
  2. {  
  3.     using Microsoft.AspNetCore.Mvc;  
  4.     using Microsoft.AspNetCore.Mvc.Filters;  
  5.     using System;  
  6.     public class ResourceFilterExampleAttribute : Attribute, IResourceFilter  
  7.     {  
  8.         public void OnResourceExecuting(ResourceExecutingContext context)  
  9.         {  
  10.             context.Result = new ContentResult()  
  11.             {  
  12.                 Content = "Resources are not available"  
  13.             };  
  14.         }  
  15.   
  16.         public void OnResourceExecuted(ResourceExecutedContext context)  
  17.         {  
  18.               
  19.         }  
  20.     }  
  21. }  
Controller Action method
  1. [ResourceFilterExampleAttribute]  
  2. public IActionResult Index()  
  3. {  
  4.      return View();  
  5. }  
Output

  
 
Action Filter
 
The Action filters run the code immediately before and after the controller action method is called. It can be used to perform any action before or after execution of the controller action method. We can also manipulate the arguments passed into an action.
 
It implements either the IActionFilter or IAsyncActionFilter interface. They are mainly used to any kind of functionality that need to perform before or after the execution of the action method. The Synchronous filters run the code before and after their pipeline stage defines OnStageExecuting and OnStageExecuted. The OnActionExecuting method is called before the action method and OnActionExecuted method is called after the action method.
 
Example 
  1. namespace BuiltinFilters.Filters  
  2. {  
  3.     using Microsoft.AspNetCore.Mvc.Filters;  
  4.     public class MyActionFilterAttribute : IActionFilter  
  5.     {  
  6.         public void OnActionExecuting(ActionExecutingContext context)  
  7.         {  
  8.             // do something before the action executes  
  9.         }  
  10.   
  11.         public void OnActionExecuted(ActionExecutedContext context)  
  12.         {  
  13.             // do something after the action executes  
  14.         }  
  15.     }  
  16. }  
ActionExecutingContext has following properties
  • ActionArguments - using this, we can manipulate the inputs to the action.
  • Controller - using this, we can manipulate the controller instance.
  • Result - Using this property, we can short circuits execution of action method. We can also prevent execution of the action method by throwing exception but it treated as a failure result instead of success result.
ActionExecutedContext has following properties
  • It contains the Controller and Result properties which is same as ActionExecutingContext.
  • Canceled - It is Boolean type. It returns true if the action execution short circuit by another filter.
  • Exception - It contain the exception information if action method or subsequent filter throw the exception.
The framework also provides an abstract ActionFilterAttribute that we can subclass. In the following example, Action filter automatically validates model state and returns if there is any error in model.
 
ModelValidate Attribute
  1. public class ModelValidateAttribute : ActionFilterAttribute  
  2. {  
  3.     public override void OnActionExecuting(ActionExecutingContext context)  
  4.     {  
  5.         if (!context.ModelState.IsValid)  
  6.         {  
  7.             context.Result = new BadRequestObjectResult(context.ModelState);  
  8.         }  
  9.     }  
  10. }  
Controller action method
  1. [Route("Home/Validatemodel")]  
  2. [HttpPost]  
  3. [ModelValidate]  
  4. public IActionResult Index3([FromBody] UserMaster user)  
  5. {  
  6.     return Ok(user);  
  7. }  

Output on fiddler

 
 
The IAsyncActionFilter interface is used to create async action filter attribute. Asynchronous filters are defined with only a single method: OnActionExecutionAsync. It takes an ActionExecutingContext and ActionExecutionDelegate as argument. Same as Synchronous filter, we can short circuit by setting Result property of ActionExecutingContext. The ActionExecutionDelegate is action method on which this attribute is applied. 
  1. public class MyActionFilterAsync : IAsyncActionFilter  
  2. {  
  3.     public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)  
  4.     {  
  5.         //Before code  
  6.         await next();  
  7.         //After code  
  8.     }  
  9. }  
Exception filters
 
The Exception filters are used to handle exceptions that occurred before anything was written to the response body. They either implement IExceptionFilter or IAsyncExceptionFilter interface. They are mostly used to apply common error handling policies for the application.
We can create our own exception filter by implementing IException interface and also we can use sub class of ExceptionFilterAttribute and override their virtual method either OnException or OnExceptionAsync.
 
Custom exception filter
  1. namespace BuiltinFilters.Filters  
  2. {  
  3.     using Microsoft.AspNetCore.Mvc;  
  4.     using Microsoft.AspNetCore.Mvc.Filters;  
  5.     using Microsoft.AspNetCore.Mvc.ModelBinding;  
  6.     using Microsoft.AspNetCore.Mvc.ViewFeatures;  
  7.     using System;  
  8.   
  9.     public class MyExceptionFilterAttribute : Attribute, IExceptionFilter  
  10.     {  
  11.         public void OnException(ExceptionContext context)  
  12.         {  
  13.             var exception = context.Exception;  
  14.             string message = string.Empty;  
  15.             if (exception.InnerException != null)  
  16.             {  
  17.                 message = exception.InnerException.Message;  
  18.             }  
  19.             else  
  20.             {  
  21.                 message = exception.Message;  
  22.             }  
  23.             // log exception here....  
  24.             var result = new ViewResult { ViewName = "Error" };  
  25.             var modelMetadata = new EmptyModelMetadataProvider();  
  26.             result.ViewData = new ViewDataDictionary(modelMetadata, context.ModelState);  
  27.             result.ViewData.Add("Exception", message);  
  28.             context.Result = result;  
  29.             context.ExceptionHandled = true;  
  30.         }  
  31.     }  
  32. }  
To demonstrate the example, I have generated the error forcefully by converting empty string to int. Following is the code for controller action method and error view.
 
Controller Action method 
  1. [Route("Home/exception")]  
  2. [MyExceptionFilter]  
  3. public IActionResult Index4()  
  4. {  
  5.     int i = Convert.ToInt32("");  
  6.     return View("Index");  
  7. }  
 Error.cshtml
  1. @{  
  2.     ViewData["Title"] = "Error";  
  3. }  
  4.   
  5. <h1 class="text-danger">Error.</h1>  
  6. <h2>Error Description</h2>  
  7. <h3>@ViewData["Exception"]</h3>  
Output

 
 
We can sub class of ExceptionFilterAttribute and override their virtual method either OnException or OnExceptionAsync.
  1. public class CustomExceptionFilterAttribute : ExceptionFilterAttribute  
  2. {  
  3.     public override void OnException(ExceptionContext context)  
  4.     {  
  5.         var exception = context.Exception;  
  6.         string message = string.Empty;  
  7.         if (exception.InnerException != null)  
  8.         {  
  9.             message = exception.InnerException.Message;  
  10.         }  
  11.         else  
  12.         {  
  13.             message = exception.Message;  
  14.         }  
  15.         // log exception here....  
  16.         var result = new ViewResult { ViewName = "Error" };  
  17.         var modelMetadata = new EmptyModelMetadataProvider();  
  18.         result.ViewData = new ViewDataDictionary(modelMetadata, context.ModelState);  
  19.         result.ViewData.Add("Exception", message);  
  20.         context.Result = result;  
  21.         context.ExceptionHandled = true;  
  22.     }  
  23. }  
Exception filter does not have before and after two events but only has a single event. They are able to handle exceptions that occur in:
  • Constructor of controller class
  • Model binding
  • Any other action filter
  • Result execution
To stop propagation of the exception, set the ExceptionContext.ExceptionHandled property to true or write a response. It cannot convert an exception in to success but action filter can do it.
 
Result filters
 
The Result filters are used to run code before or after the execution of controller action results. They are executed only if the controller action method has been executed successfully. They implement either the IResultFilter or IAsyncResultFilter interface and their execution surrounds the execution of action results.
 
The Result filter is only executed for successful action result generated by action method or action filter. It is not executed if exception filter handles the exception and returns result. We can short circuit execution of action result using OnResultExecuting method by setting ResultExecutingContext.Cancel to true. We need to write response object when we short-circuit action result to avoid generating empty response. The OnResultExecuted method runs the response already sent to the client and cannot be changed unless an exception is thrown. The property ResultExecutedContext.Canceled will be set to true, if another filter short-circuits the action result execution.
The property ResultExecutedContext.Exception will be set to non-null value, if exception was thrown by the action result or subsequent result filter, we can effectively handle the exception and prevent the exception being re-thrown (by MVC) in pipeline by setting this property to null. If we are handling the exception in a result filter, we might not be able to write anything to the response.
 
Result Filter Example

In the following example I have created, result filter adds author name to response header. The value of the author attribute is set at action level.
 
Result Filter
  1. namespace BuiltinFilters.Filters  
  2. {  
  3.     using Microsoft.AspNetCore.Mvc.Filters;  
  4.     using System;  
  5.     public class SetAuthorAttribute : Attribute, IResultFilter  
  6.     {  
  7.         string _value;  
  8.         public SetAuthorAttribute(string value)  
  9.         {  
  10.             _value = value;  
  11.         }  
  12.         public void OnResultExecuted(ResultExecutedContext context)  
  13.         {  
  14.   
  15.         }  
  16.   
  17.         public void OnResultExecuting(ResultExecutingContext context)  
  18.         {  
  19.             context.HttpContext.Response.Headers.Add("Author"new string[] { _value });  
  20.         }  
  21.     }  
  22. }  
Action Method
  1. [Route("Home/resultfilter")]  
  2. [SetAuthor("Test Value")]  
  3. public IActionResult Index6()  
  4. {  
  5.     return View("Index");  
  6. }  
Output

 
 
Aside from this we can create asynchronous result filter and also create sub class from built in filter attribute: ResultFilterAttribute.
 
Note

To run example code, download the attachment and execute “dotnet restore” command or download the dependencies before running the application.
 
Summary
 
The ASP.net core MVC includes five built-in filter types that we can create custom filters as well as sub class based on our requirement.

Up Next
    Ebook Download
    View all
    Learn
    View all