Filters (Action, Authorization, Exception, Resource, Result)
Mind Map Summary
- ASP.NET Core Filters
- Definition: A feature of the MVC/API framework that allows you to run code before or after specific stages in the action execution pipeline.
- Purpose: To handle cross-cutting concerns like logging, error handling, authorization, and caching without duplicating code in action methods.
- Key Difference from Middleware: Filters are part of the MVC/API framework and have access to the MVC context (like
ActionArguments
andActionResult
). Middleware is more low-level and only has access toHttpContext
.
- Filter Types (in order of execution)
- Authorization Filters (
IAuthorizationFilter
)- Runs: First.
- Use Case: To determine if a request is authorized. Can short-circuit if unauthorized.
- Resource Filters (
IResourceFilter
)- Runs: After authorization. Wraps the rest of the pipeline.
- Use Case: Caching. Can short-circuit to return a cached response.
- Action Filters (
IActionFilter
)- Runs: Immediately before and after the action method executes.
- Use Case: The most common filter type. Used for logging, model validation, and manipulating action arguments or results.
- Exception Filters (
IExceptionFilter
)- Runs: Only if an unhandled exception occurs in an action method or another filter.
- Use Case: Global error handling for the MVC/API pipeline.
- Result Filters (
IResultFilter
)- Runs: Immediately before and after an action result is executed.
- Use Case: Modifying the response, such as adding headers or formatting the output.
- Authorization Filters (
Core Concepts
1. What are Filters?
Filters are a powerful feature designed to address cross-cutting concerns. They provide a way to hook into the MVC action invocation pipeline, allowing you to execute code at various stages. This helps keep your action methods clean and focused on their core business logic, while concerns like logging, authorization, or error handling are managed globally or declaratively through attributes.
2. The Filter Pipeline
Within the broader ASP.NET Core request pipeline, after the routing middleware has selected which controller and action method to execute, the request is passed to the filter pipeline. The flow is as follows:
- Authorization Filter: Checks permissions.
- Resource Filter: Runs code at the beginning. Useful for caching.
- Model Binding: The framework binds parameters for the action method.
- Action Filter: Runs code just before the action method.
- Action Method Execution: The actual controller action method runs.
- Action Filter: Runs code just after the action method completes.
- Result Filter: Runs code before the
ActionResult
is executed. - Result Execution: The
ActionResult
(e.g.,Ok()
,View()
) is executed to generate the response. - Result Filter: Runs code after the result has been executed.
- Resource Filter: Runs code at the very end.
If an exception occurs, the normal flow is interrupted, and Exception Filters are executed.
Practice Exercise
Create a custom Action Filter attribute that logs the time it takes for an action method to execute. Apply this filter to a controller action and verify that it logs the timing information correctly.
Answer
Code Example
1. The Custom Action Filter Attribute
// LogExecutionTimeAttribute.cs
using Microsoft.AspNetCore.Mvc.Filters;
using System.Diagnostics;
// We inherit from ActionFilterAttribute to create our custom filter
public class LogExecutionTimeAttribute : ActionFilterAttribute
{
private Stopwatch _stopwatch;
// 1. This runs BEFORE the action method
public override void OnActionExecuting(ActionExecutingContext context)
{
_stopwatch = Stopwatch.StartNew();
}
// 2. This runs AFTER the action method
public override void OnActionExecuted(ActionExecutedContext context)
{
_stopwatch.Stop();
var executionTime = _stopwatch.ElapsedMilliseconds;
// Log the information (in a real app, use ILogger)
Console.WriteLine($"Action '{context.ActionDescriptor.DisplayName}' executed in {executionTime} ms");
}
}
2. The Controller and Action
// DemoController.cs
using Microsoft.AspNetCore.Mvc;
using System.Threading;
[ApiController]
[Route("[controller]")]
public class DemoController : ControllerBase
{
[HttpGet]
[LogExecutionTime] // Apply the filter attribute here
public IActionResult Get()
{
// Simulate some work
Thread.Sleep(150);
return Ok("Action finished successfully.");
}
}
3. Program.cs
Configuration
No special registration is needed for attribute-based filters beyond the standard controller setup.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers(); // This is sufficient
var app = builder.Build();
app.MapControllers();
app.Run();
Explanation
LogExecutionTimeAttribute
: We create a class that inherits fromActionFilterAttribute
. This makes it a valid attribute that can be placed on controllers or action methods.OnActionExecuting
: This method is part of theIActionFilter
interface and is called by the MVC framework before the target action method (Get()
in our case) is executed. We use this hook to start aStopwatch
.OnActionExecuted
: This method is called after the action method has finished executing but before theActionResult
is processed. We use this hook to stop theStopwatch
and log the elapsed time. We have access to theActionExecutedContext
, which gives us rich information about the action that just ran, including its name viaActionDescriptor.DisplayName
.- Applying the Filter: We simply decorate the
Get
action method with our[LogExecutionTime]
attribute. The MVC framework discovers this attribute and ensures the filter’s methods are called at the appropriate times.
When you run the API and make a GET request to /demo
, the console will output a message similar to this, verifying that the filter worked correctly:
Action 'YourProjectName.Controllers.DemoController.Get (YourProjectName)' executed in 152 ms