Filters in ASP.NET Core allow you to run code before or after specific stages in the request processing pipeline. They provide a way to handle cross-cutting concerns like authorization, caching, exception handling, and logging.
Types of Filters in ASP.NET Core
1. Authorization Filters
Run first and determine whether the user is authorized for the request.
Example:
public class CustomAuthFilter : IAuthorizationFilter { public void OnAuthorization(AuthorizationFilterContext context) { if (!context.HttpContext.User.Identity.IsAuthenticated) { context.Result = new UnauthorizedResult(); } } }
2. Resource Filters
Run after authorization and can short-circuit the pipeline.
Example:
public class CustomResourceFilter : IResourceFilter { public void OnResourceExecuting(ResourceExecutingContext context) { // Before the action executes if (!context.HttpContext.Request.Headers.ContainsKey("X-Custom-Header")) { context.Result = new BadRequestObjectResult("Missing required header"); } } public void OnResourceExecuted(ResourceExecutedContext context) { // After the action executes } }
3. Action Filters
Run immediately before and after an action method is called.
Example:
public class LogActionFilter : IActionFilter { public void OnActionExecuting(ActionExecutingContext context) { Console.WriteLine($"Action {context.ActionDescriptor.DisplayName} is starting"); } public void OnActionExecuted(ActionExecutedContext context) { Console.WriteLine($"Action {context.ActionDescriptor.DisplayName} completed"); } }
4. Exception Filters
Handle exceptions that occur in the pipeline.
Example:
public class CustomExceptionFilter : IExceptionFilter { public void OnException(ExceptionContext context) { if (context.Exception is UnauthorizedAccessException) { context.Result = new ObjectResult("Custom error message") { StatusCode = 403 }; context.ExceptionHandled = true; } } }
5. Result Filters
Run before and after the execution of action results.
Example:
public class CustomResultFilter : IResultFilter { public void OnResultExecuting(ResultExecutingContext context) { // Before the result executes if (context.Result is ViewResult viewResult) { viewResult.ViewData["CustomData"] = "Added in filter"; } } public void OnResultExecuted(ResultExecutedContext context) { // After the result executes } }
Registering Filters
You can register filters at different levels:
- Globally (applies to all actions):
services.AddControllers(options => { options.Filters.Add(new CustomAuthFilter()); });
- At controller level:
[ServiceFilter(typeof(CustomAuthFilter))] public class HomeController : Controller { // ... }
- At action level:
[TypeFilter(typeof(LogActionFilter))] public IActionResult Index() { return View(); }
Differences Between Filters and Middleware in ASP.NET Core
Feature | Filters | Middleware |
---|---|---|
Scope | Operate within the MVC pipeline | Operate on the entire request pipeline |
Execution Order | Run after middleware in the request pipeline | Run before filters in the request pipeline |
Access to MVC Context | Have access to MVC-specific context (ActionContext, ResultContext) | Only have access to HttpContext |
Lifecycle | New instance per request (unless explicitly registered as singleton) | Typically singleton (one instance for all requests) |
Usage | Handle MVC-specific concerns (action execution, model binding, etc.) | Handle lower-level concerns (request/response, headers, compression, etc.) |
Registration | Added in MVC options or as attributes | Added in Configure method of Startup.cs |
When to Use | When you need MVC context or want to affect MVC-specific behavior | When you need to process all requests regardless of MVC |
Example of Middleware:
public class CustomMiddleware { private readonly RequestDelegate _next; public CustomMiddleware(RequestDelegate next) { _next = next; } public async Task InvokeAsync(HttpContext context) { // Before the next middleware Console.WriteLine("Middleware - Before next"); await _next(context); // After the next middleware Console.WriteLine("Middleware - After next"); } } // In Startup.cs public void Configure(IApplicationBuilder app) { app.UseMiddleware<CustomMiddleware>(); // Other middleware app.UseMvc(); }
Key Difference in Execution Flow:
- Middleware executes first (in the order they’re registered)
- Then Authorization Filters
- Then Resource Filters
- Then Action Filters (before action execution)
- Then the action method executes
- Then Action Filters (after action execution)
- Then Exception Filters (if there’s an exception)
- Then Result Filters
- Then middleware runs again in reverse order
Filters are more tightly integrated with MVC and have access to MVC-specific context, while middleware operates at a lower level across all requests.