What are action filters and how do you create custom filters?
4 minintermediateASP.NET-Corefilterscross-cutting
Quick Answer
Action filters run custom logic at stages of the MVC action pipeline, ideal for cross-cutting concerns (logging, validation, caching, exception handling). The filter types run in order: Authorization, Resource, Action, Exception, and Result filters. You create one by implementing an interface like `IActionFilter`/`IAsyncActionFilter` (or deriving from `ActionFilterAttribute`) and registering it globally, on a controller, or on an action.
Detailed Answer
Action filters are attributes that add extra processing logic before or after specific stages in the request processing pipeline. They allow cross-cutting concerns like logging, caching, authorization, and exception handling.
Filter types and execution order:
- Authorization filters - Run first, verify authorization
- Resource filters - Run after authorization, good for caching
- Action filters - Run before and after action method execution
- Exception filters - Handle exceptions
- Result filters - Run before and after result execution
Creating a custom action filter:
// Method 1: Inherit from ActionFilterAttribute
public class LogActivityFilter : ActionFilterAttribute
{
private readonly ILogger _logger;
public LogActivityFilter(ILogger logger)
{
_logger = logger;
}
public override void OnActionExecuting(ActionExecutingContext context)
{
_logger.LogInformation($"Executing action: {context.ActionDescriptor.DisplayName}");
base.OnActionExecuting(context);
}
public override void OnActionExecuted(ActionExecutedContext context)
{
_logger.LogInformation($"Executed action: {context.ActionDescriptor.DisplayName}");
base.OnActionExecuted(context);
}
}
// Method 2: Implement IActionFilter interface
public class ValidateModelFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
if (!context.ModelState.IsValid)
{
context.Result = new BadRequestObjectResult(context.ModelState);
}
}
public void OnActionExecuted(ActionExecutedContext context)
{
// Logic after action execution
}
}
// Async version
public class AsyncLoggingFilter : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(
ActionExecutingContext context,
ActionExecutionDelegate next)
{
// Before action execution
await next(); // Execute the action
// After action execution
}
}
Using filters:
// Apply to specific action
[LogActivityFilter]
public IActionResult GetUser(int id)
{
return Ok();
}
// Apply to controller
[ValidateModelFilter]
public class UsersController : ControllerBase
{
}
// Register globally in Program.cs
builder.Services.AddControllers(options =>
{
options.Filters.Add();
});