ASP.NET Core 2.0 MVC Filters

Problem

How to run code before and after MVC request pipeline in ASP.NET Core.

Solution

In an empty project, update the Startup class to add services and middleware for MVC.

Add the class to implement filter.

In the Home controller add an action method that uses Action filter,

Browse to /Home/ParseParameter; you’ll see -


Discussion

Filter runs after an action method has been selected to execute. MVC provides built-in filters for things like authorization and caching. Custom filters are very useful to encapsulate the reusable code that you want to run before or after the action methods.

Filters can short-circuit the result, i.e., stop the code in your action from running and return a result to the client. They can also have services injected into them via service container, which makes them very flexible.

Filter Interfaces

Creating a custom filter requires implementation of an interface for the type of filter you require. There are two flavors of interfaces for most filter type - synchronous and asynchronous.

You can short-circuit the filter pipeline by setting the Result (of type IActionResult) property on the context parameter (for Async filters, don’t call the next delegate).

For Result filters, you could short-circuit by setting the Cancel property on context parameter and sending a response.

  1. public void OnResultExecuting(ResultExecutingContext context)  
  2. {  
  3.     context.Cancel = true;  
  4.     context.HttpContext.Response.WriteAsync("I'll skip the result execution");  
  5. }  
  6.   
  7. [SkipResultFilter]  
  8. public IActionResult SkipResult()  
  9. {  
  10.     return Content("Hello SkipResult");  
  11. }  
Filter Attributes

MVC provides abstract base classes that you can inherit from to create custom filters. These abstract classes inherit from Attribute class and therefore can be used to decorate Controllers and action methods.

  • ActionFilterAttribute
  • ResultFilterAttribute
  • ExceptionFilterAttribute
  • ServiceFilterAttribute
  • TypeFilterAttribute
Filter Types

There are various types of filters that run at different stages of the filter pipeline. Below, a figure from official documentation illustrates the sequence: 

 

Authorization

This is the first filter to run and short circuit the request for unauthorized users. They only have one method (unlike most other filters that have Executing and Executed methods). Normally, you won’t write your own Authorization filters, the built-in filter calls into framework’s authorization mechanism.

Resource

They run before model binding and can be used for changing how it behaves. Also, they run after the result has been generated and can be used for caching etc.

Action

They run before and after the action method, thus are very useful to manipulate the action parameters or its result. The context supplied to these filters lets you manipulate the action parameters, controller and result.

Exception

They can be used for unhandled exception before they’re written to the response. Exception handling middleware works for most scenarios however this filter can be used if you want to handle errors differently based on the invoked action.

Result

They run before and after the execution of action method’s result, if the result was successful. They can be used to manipulate the formatting of the result.

Filter Scope

Filters can be added at different levels of scope: Action, Controller and Global. Attributes are used for action and controller level scope. For globally scoped filters you need to add them to filter collection of MvcOptions when configuring services in Startup,

Filters are executed in a sequence

  1. The Executing methods are called first for Global > Controller > Action filters.
  2. Then Executed methods are called for Action > Controller > Global filters.
Filter Dependency Injection

In order to use filters that require dependencies injected at runtime, you need to add them by Type. You can add them globally (as illustrated above), however, if you want to apply them to action or controller (as attributes) then you have two options:

ServiceFilterAttribute

This attributes retrieves the filter using service container. To use it,

Create a filter that uses dependency injection

  1. public class GreetingServiceFilter : IActionFilter  
  2.  {  
  3.      private readonly IGreetingService greetingService;  
  4.   
  5.      public GreetingServiceFilter(IGreetingService greetingService)  
  6.      {  
  7.          this.greetingService = greetingService;  
  8.      }  
  9.   
  10.      public void OnActionExecuting(ActionExecutingContext context)  
  11.      {  
  12.          context.ActionArguments["param"] =   
  13.              this.greetingService.Greet("James Bond");  
  14.      }  
  15.   
  16.      public void OnActionExecuted(ActionExecutedContext context)  
  17.      { }  
  18.  }  

Add filter to service container

Apply it using ServiceFilterAttribute

TypeFilterAttribute

This attributes doesn’t need registering the filter in service container and initiates the type using ObjectFactory delegate. To use it

Create a filter that uses dependency injection

Apply it using TypeFilterAttribute.

You could also inherit from TypeFilterAttribute and then use without TypeFilter,

Source Code

GitHub