Filters

Filters are the code blocks that execute before / after specific stages in “Filter Pipeline”.

Filters perform specific tasks such as authorization, caching, exeption handling etc.

Filter Pipeline

Overview of Types of Filters

Authorization Filter

Determines whether the user is authorized to access the action method.

Resource Filter

Invoking custom model binder explicitly

Caching the response.

Action Filter

Manipulating & validating the action method parameters.

Manipulating the ViewData.

Overriding the IActionResult provided by action method.

Exception Filter

Handling unhandled exception that occur in model binding, action filters or action methods.

Result Filter

Preventing IActionResult from execution.

Adding last-moment changes to response (such as adding response headers).

Action Filter

When it runs

Runs immediately before and after an action method executes.

‘OnActionExecuting’ method

  • It can access the action method parameters, read them & do necessary manipulations on them.
  • It can validate action method parameters.
• It can short-circuit the action (prevent action method from execution) and return a different IActionResult.

‘OnActionExecuted’ method

  • It can manipulate the ViewData.
  • It can change the result returned from the action method.

Filter Arguments

Global Filters

Filter Scopes

What are global filters?

Global filters are applied to all action methods of all controllers in the project.

How to add global filters in Program.cs?

builder.Services.AddControllersWithViews(options => {
options.Filters.Add<FilterClassName>(); //add by type
//or
options.Filters.Add(new FilterClassName()); //add filter instance
});

Default Order of Filter Execution

Custom Order of Filters

IOrderedFilter

Example

IOrderedFilter

Action filter with IOrderedFilter

Order = order;

public class FilterClassName : IActionFilter, IOrderedFilter
{
public int Order { get; set; } //Defines sequence of execution
public FilterClassName(int order)
{
}
public void OnActionExecuting(ActionExecutingContext context)
{
//TO DO: before logic here
}
public void OnActionExecuted(ActionExecutedContext context)
{
//TO DO: after logic here
}
}

Async Filters

Asynchronous Action Filter

Order = order;

public class FilterClassName : IAsyncActionFilter, IOrderedFilter
{
public int Order { get; set; } //Defines sequence of execution
public FilterClassName(int order)
{
}
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
//TO DO: before logic here
await next();
//TO DO: after logic here
}
}

Short-circuiting Filters

Action Filters

When it runs

Runs immediately before and after an action method executes.

‘OnActionExecuting’ method

  • It can access the action method parameters, read them & do necessary manipulations on them.
  • It can validate action method parameters.
• It can short-circuit the action (prevent action method from execution) and return a different IActionResult.

‘OnActionExecuted’ method

  • It can manipulate the ViewData.
  • It can change the result returned from the action method.
• It can throw exceptions to either return the exception to the exception filter (if exists); or return the error response to the browser.

Short-Circuiting Action Filter

Order = order;

public class FilterClassName : IAsyncActionFilter, IOrderedFilter
{
public int Order { get; set; } //Defines sequence of execution
public FilterClassName(int order)
{
}
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
//TO DO: before logic here
context.Result = some_action_result; //you can return any type of IActionResult
//Not calling next(). So it leads remaining filters & action method short-circuited.
}
}

Short-Circuiting (exit) the filters

Result Filter

When it runs

  • Runs immediately before and after an IActionResult executes.
  • It can access the IActionResult returned by the action method.

‘OnResultExecuting’ method

  • It can continue executing the IActionResult normally, by not assigning “Result” property of the context.
• It can short-circuit the action (prevent IActionResult from execution) and return a different IActionResult.

‘OnResultExecuted’ method

  • It can manipulate the last-moment changes in the response, such as adding necessary response headers.
  • It should not throw exceptions because, exceptions raised in result filters would not be caught by the exception filter.

Synchronous Result Filter

Order = order;

public class FilterClassName : IResultFilter, IOrderedFilter
{
public int Order { get; set; } //Defines sequence of execution
public FilterClassName(int order)
{
}
public void OnResultExecuting(ResultExecutingContext context)
{
//TO DO: before logic here
}
public void OnResultExecuted(ResultExecutedContext context)
{
//TO DO: after logic here
}
}

Asynchronous Result Filter

Order = order;

public class FilterClassName : IAsyncResultFilter, IOrderedFilter
{
public int Order { get; set; } //Defines sequence of execution
public FilterClassName(int order)
{
}
public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
{
//TO DO: before logic here
await next();
//TO DO: after logic here
}
}

Resource Filter

When it runs

Runs immediately after Authorize Filter and after Result Filter executes.

‘OnResourceExecuting’ method

  • It can do some work before model binding. Eg: Adding metrics to an action method. Eg: Short-circuit if an unsupported content type is requested.
• It can change the way how model binding works (invoking a custom model binder explicitly).
• It can short-circuit the action (prevent IActionResult from execution) and return a different IActionResult.

‘OnResourceExecuted’ method

  • It can read the response body and store it in cache.

Synchronous Resource Filter

Order = order;

public class FilterClassName : IResourceFilter, IOrderedFilter
{
public int Order { get; set; } //Defines sequence of execution
public FilterClassName(int order)
{
}
public void OnResourceExecuting(ResourceExecutingContext context)
{
//TO DO: before logic here
}
public void OnResourceExecuted(ResourceExecutedContext context)
{
//TO DO: after logic here
}
}

Asynchronous Resource Filter

Order = order;

public class FilterClassName : IAsyncResourceFilter, IOrderedFilter
{
public int Order { get; set; } //Defines sequence of execution
public FilterClassName(int order)
{
}
public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next)
{
//TO DO: before logic here
await next();
//TO DO: after logic here
}
}

Authorization Filter

Authorization Filters

Runs before any other filters in the filter pipeline.

‘OnAuthorize’ method

  • Determines whether the user is authorized for the request.
  • Short-circuits the pipeline if the request is NOT authorized.
  • Don’t throw exceptions in OnAuthorize method, as they will not be handled by exception filters.

Synchronous Authorization Filter

public class FilterClassName : IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
//TO DO: authorization logic here
}
}

Asynchronous Authorization Filter

public class FilterClassName : IAsyncAuthorizationFilter
{
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
//TO DO: authorization logic here
}
}

Exception Filter

When it runs

Runs when an exception is raised during the filter pipeline.

‘OnException method

  • Handles unhandled exceptions that occur in controller creation, model binding, action filters or action methods.
  • Doesn’t handle the unhandled exceptions that occur in authorization filters, resource filters, result filters or IActionResult execution.
  • Recommended to be used only when you want a different error handling and generate different result for specific controllers; otherwise, ErrorHandlingMiddleware is recommended over Exception Filters.

Synchronous Exception Filter

public class FilterClassName : IAsyncExceptionFilter
{
public async Task OnExceptionAsync(ExceptionFilterContext context)
{
//TO DO: exception handling logic here, as follows
context.Result = some_action_result;
//or
context.ExceptionHandled = true;
return Task.CompletedTask;
}
}

Asynchronous Exception Filter

public class FilterClassName : IAsyncExceptionFilter
{
public async Task OnExceptionAsync(ExceptionFilterContext context)
{
//TO DO: exception handling logic here, as follows
context.Result = some_action_result;
//or
context.ExceptionHandled = true;
return Task.CompletedTask;
}
}

Impact of Short-Circuiting

Short-circuiting Authorization Filter

Short-circuiting Resource Filter

Short-circuiting Action Filter

Short-circuiting Exception Filter

Short-circuiting Result Filter

Short-circuiting the filters

AlwaysRun Result Filter

Short-circuiting Authorization Filter

Short-circuiting Resource Filter

Short-circuiting Action Filter

Short-circuiting Exception Filter

Short-circuiting Result Filter

When AlwaysRunResultFilter runs

Runs immediately before and after result filters.

Result filters:

Doesn’t execute when authorization filter, resource filter or exception filter short-circuits.

AlwaysRunResult filter:

Execute always even when authorization filter, resource filter or exception filter short-circuits.

‘OnResultExecuting’ method

Same as Result filter

’OnResultExecuted’ method

Same as Result filter

Synchronous Always Run Result Filter

public class FilterClassName : IAlwaysRunResultFilter
{
public void OnResultExecuting(ResultExecutingContext context)
{
//TO DO: before logic here
}
public void OnResultExecuted(ResultExecutedContext context)
{
//TO DO: after logic here
}
}

Asynchronous Always Run Result Filter

public class FilterClassName : IAsyncAlwaysRunResultFilter
{
public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
{
//TO DO: before logic here
await next();
//TO DO: after logic here
}
}

Filter Overrides

[TypeFilter(typeof(FilterClassName))] //filter applied at controller level
public class ControllerName : Controller
{
public IActionResult Action1() //requirement: The filter SHOULD execute
{
}
public IActionResult Action2() //requirement: The filter SHOULD NOT execute. But how??
{
}
}

Attribute to be applied to desired action method

public class SkipFilterAttribute : Attribute, IFilterMetadata
{
}

Action method

[SkipFilter]

public IActionResult ActionMethod()
{
}

Filter that respects ‘SkipFilterAttribute’

return;

It skips execution of code of a filter, for specific action methods.

public class FilterClassName : IActionFilter //or any other filter interface
{
public void OnActionExecuting(ActionExecutingContext context)
{
//get list of filters applied to the current working action method
if (context.Filters.OfType<SkipResultFilter>().Any())
{
}
//TO DO: before logic here
}
public void OnActionExecuted(ActionExecutedContext context)
{
//TO DO: after logic here
}
}

[ServiceFilter]

Common purpose

Both are used to apply a filter a controller or action method.

Type Filter Attribute

//can supply arguments to filter
[TypeFilter(typeof(FilterClassName), Arguments = new object[] { arg1, arg2 })]
public IActionResult ActionMethod()
{
}

Service Filter Attribute

//can't supply arguments to filter
[ServiceFilter(typeof(FilterClassName))]
public IActionResult ActionMethod()
{
}

Type Filter

  • Can supply arguments to the filter.
  • Filter instances are created by using Microsoft.Extensions.DependencyInjection. ObjectFactory.
  • But optionally, you can re-use the same instance of filter class across multiple requests, by setting a property called TypeFilterAttribute.IsReusable to ‘true’.
  • Filter classes CAN inject services using both constructor injection or method injection.
• They're NOT created using DI (Dependency Injection).
• The lifetime of filter instances is by default transient (a new filter instance gets created every time when it is invoked).
Filter classes NEED NOT be registered (added) to the IoC container.

Service Filter

  • Can’t supply arguments to the filter.
• Filter instances are created by using ServiceProvider (using DI).
  • The lifetime of filter instances is the actual lifetime of the filter class added in the IoC container.
  • Filter classes CAN inject services using both constructor injection or method injection.
Eg: If the filter class is added to the IoC container with AddScoped() method, then its instances are scoped.
• Filter class SHOULD be registered (added) to the IoC container, much like any other service.

Filter attribtute classes

IActionFilter [vs] ActionFilterAttribute

[versus]

Action filter that implements ‘IActionFilter’

public class FilterClassName : IActionFilter, IOrderedFilter
{
//supports constructor DI
}

Action filter that inherits ‘ActionFilterAttribute’

public class FilterClassName : ActionFilterAttribute
{
//doesn't support constructor DI
}

Filter interfaces:

  • IAuthorizationFilter
  • IResourceFilter
  • IActionFilter
  • IExceptionFilter
  • IResultFilter
  • IAsyncAuthorizationFilter
  • IAsyncResourceFilter
  • IAsyncActionFilter
  • IAsyncExceptionFilter
  • IAsyncResultFilter

Filter attributes:

  • ActionFilterAttribute
  • ExceptionFilterAttribute
  • ResultFilterAttribute

Action filter that implements ‘IActionFilter’

public class FilterClassName : IActionFilter, IOrderedFilter
{
public int Order { get; set; }
public FilterClassName(IService service, type arg)
{
}
public void OnActionExecuting(ActionExecutingContext context)
{
}
public void OnActionExecuted(ActionExecutedContext context)
{
}
}
[TypeFilter(typeof(FilterClassName),
Arguments = new object[] { arg1, … })]

Action filter that inherits ‘ActionFilterAttribute’

public class FilterClassName : ActionFilterAttribute
{
public FilterClassName(type arg)
{
}
public override void OnActionExecuting(ActionExecutingContext context)
{
}
public override void OnActionExecuted(ActionExecutedContext context)
{
}
}
[FilterClassName(arg1, … )]

Internal definitions of IActionFilter and ActionFilterAttribute

IActionFilter

namespace Microsoft.AspNetCore.Mvc.Filters
{
public interface IActionFilter : IFilterMetadata
{
void OnActionExecuting(ActionExecutingContext context);
void OnActionExecuted(ActionExecutedContext context);
}
}

ActionFilterAttribute

namespace Microsoft.AspNetCore.Mvc.Filters
{
public class ActionFilterAttribute : Attribute, IActionFilter, IAsyncActionFilter, IOrderedFilter, IResultFilter, IAsyncResultFilter
{
public virtual void OnActionExecuting(ActionExecutingContext context) { }
public virtual void OnActionExecuted(ActionExecutedContext context) { }
public virtual void OnResultExecuting(ActionExecutingContext context) { }
public virtual void OnResultExecuted(ActionExecutedContext context) { }
public virtual Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { }
public virtual Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next) { }
public int Order { get; set; }
}
}

Filter interface [vs] FilterAttribute class

Filter interface [such as IActionFilter, IResultFilter etc.]

  • Filter class MUST implement all methods - both “Executing” and “Executed” methods.

  • Filter class CAN have DI with either constructor injection or method injection.

  • Doesn’t implement “Attribute” class.

  • Filter should be applied to controller or action methods by using [ServiceFilter] or [TypeFilter] attributes; otherwise can be applied as global filter in the Program.cs. Eg: [TypeFilter(typeof(FilterClassName))] //lengthy

  • Filter class can receive arguments only through constructor parameters; but only with [TypeFilter] attribute; not with [ServiceFilter] attribute.

FilterAttribute class [such as ActionFilterAttribute etc.]

• Filter class MAY override desired (either or both methods - "Executing" and "Executed") methods.
  • Filter class CAN’T have DI with neither constructor injection nor method injection.
  • FilterAttribute class [such as ActionFilterAttribute etc.]
• Filter can be applied to controller or action methods by directly using the filter class name itself (without using [ServiceFilter] or [TypeFilter] attributes); otherwise can be applied as global filter in the Program.cs.
  • Eg: [FilterClassName] //simple
  • Filter class can receive arguments either through constructor parameters or filter class’s properties.

IFilterFactory

Filter factory that inherits ‘IFilterFactory’

public class FilterClassNameAttribute : Attribute,

IFilterFactory

this.Prop1 = arg1; this.Prop2 = arg2;

{
public type Prop1 { get; set; }
public FilterClassName(type arg1, type arg2)
{
}
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
{
FilterClassName filter = serviceProvider.GetRequiredService<FilterClassName>(); //instantiate the filter
filter.Property1 = Prop1;
return filter;
}
}
[FilterClassName(arg1, arg2, … )]

Action filter that inherits ‘ActionFilterAttribute’

public class FilterClassName : ActionFilterAttribute
{
public FilterClassName(type arg1, type arg2)
{
}
public override void OnActionExecuting(ActionExecutingContext context)
{
}
public override void OnActionExecuted(ActionExecutedContext context)
{
}
}
[FilterClassName(arg1, arg2, … )]

IFilterFactory

IFilterMetadata CreateInstance(IServiceProvider serviceProvider);

namespace Microsoft.AspNetCore.Mvc.Filters
{
public interface IFilterFactory : IFilterMetadata
{
bool IsReusable { get; }
}
}

FilterAttribute class [such as ActionFilterAttribute etc.]

  • Filter CAN be applied as an attribute to the controller or action method. Eg: [FilterClassName]
  • Filter class CAN’T have DI with neither constructor injection nor method injection.
  • Filter class CAN receive arguments either through constructor parameters or filter class’s properties.

IFilterFactory

  • Filter CAN be applied as an attribute to the controller or action method. Eg: [FilterClassName]
  • Filter class CAN have DI with either constructor injection or method injection.
• Filter class CAN receive arguments only through filter class's properties, if it is instantiated through ServiceProvider (using DI).

Alternatively, if you don’t need to inject services using DI in the filter class; you can instantiate the filter class with ‘new’ keyword, in the CreateInstance() method of IFilterFactory; then the filter class can receive arguments either as constructor parameters or properties.

Filters [vs] Middleware

Middleware

Middleware pipeline is a superset of Filter pipeline, which contains the full-set of all middlewares added to the ApplicationBuilder in the application’s startup code (Program.cs).

Middleware pipeline execute for all requests.

Middleware handles application-level functionality such as Logging, HTTPS redirection, Performance profiling, Exception handling, Static files, Authentication etc., by accessing low-level abstractions such as HttpContext.

Filter

Filter pipeline is a subset of Middleware pipeline which executes under “EndPoint Middleware”.

In addition, filter pipeline executes for requests that reach “EndPoint Middleware”.

Filters handle MVC-specific functionality such as manipulating or accessing ViewData, ViewBag, ModleState, Action result, Action parameters etc.

Middleware Pipeline