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 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 authorisation and caching. Custom filters are very useful to encapsulate reusable code that you want to run before or after action methods.

Filters can short-circuit the result i.e. stops 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 implementing an interface for the type of filter you require. There are two flavours 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 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:

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 type 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 circuits request for unauthorised 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 authorisation 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 useful to manipulate action parameters or its result. The context supplied to these filters let 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 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:

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: https://github.com/TahirNaushad/Fiver.Mvc.Filters

Leave a Reply