Filters
Level: Intermediate
Filters are hooks around controller execution. Learn them after controllers, action results, and model binding because filters are mainly used with MVC/Web API controllers.
- Filter definition: Code that runs before and/or after controller actions (cross-cutting concerns)
- Cross-cutting concern: Code needed by many actions but not business logic (logging, auth, timing)
- Authorization filters: Run first, check permissions, can short-circuit ([Authorize] attribute)
- Resource filters: Run before model binding, before action (caching, validation)
- Action filters: Run before and after action (logging request/response, modifying results)
- Result filters: Run before/after result execution (result transformation)
- Exception filters: Catch exceptions thrown by action (centralized error handling)
[Authorize]filter: Built-in, stops pipeline if user not authenticated, returns 401[Authorize(Roles = "Admin")]: Only admins can execute this action- School Management filter examples: [LogActivity] logs action to audit table, [ValidateStudent] checks student exists
- Global filters: Register in Program.cs, apply to all actions (error handling, logging)
- Action filters with attributes:
[ServiceFilter(typeof(LoggingFilter))]on specific actions - Filter order: Authorization → Resource → Action (before) → Handler → Action (after) → Result
- Common use: Logging (what API was called, how long it took), caching (GET requests cache 5 minutes)
- When not to use filters: Simple business logic (put in services), one-time validations (use action result checks instead)
What is a Filter?
A filter is code that runs before or after controller actions.
Example use cases:
- log every API call
- validate a custom header
- handle exceptions
- add response headers
- measure execution time
- check permissions
These are called cross-cutting concerns because they apply across many actions.
Filter Pipeline
For a controller action, ASP.NET Core can run filters around the action.
Simplified flow:
Request
-> Authorization filters
-> Resource filters
-> Action filters
-> Controller action
-> Result filters
-> Response
Exception filters can handle exceptions from action execution.
Types of Filters
| Filter Type | Runs | Common Use |
|---|---|---|
| Authorization filter | Early | Check access |
| Resource filter | Before model binding/action | Caching, short-circuiting |
| Action filter | Before and after action method | Logging, validation, timing |
| Exception filter | When exception occurs | Convert exceptions to responses |
| Result filter | Before and after result execution | Modify response |
Action Filter Example
This filter measures how long each action takes.
Register a Global Filter
builder.Services.AddControllers(options =>
{
options.Filters.Add<ExecutionTimeFilter>();
});
Global filters apply to all controllers and actions.
Register Filter Service
If your filter uses dependency injection, register it:
builder.Services.AddScoped<ExecutionTimeFilter>();
Then use it:
builder.Services.AddControllers(options =>
{
options.Filters.AddService<ExecutionTimeFilter>();
});
Use Filter on One Controller
[ServiceFilter(typeof(ExecutionTimeFilter))]
[ApiController]
[Route("api/students")]
public class StudentsController : ControllerBase
{
}
This applies the filter only to StudentsController.
Use Filter on One Action
[HttpGet("{id}")]
[ServiceFilter(typeof(ExecutionTimeFilter))]
public IActionResult GetStudent(int id)
{
return Ok();
}
This applies the filter only to one action.
Exception Filter Example
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
public class ApiExceptionFilter : IExceptionFilter
{
private readonly ILogger<ApiExceptionFilter> _logger;
public ApiExceptionFilter(ILogger<ApiExceptionFilter> logger)
{
_logger = logger;
}
public void OnException(ExceptionContext context)
{
_logger.LogError(
context.Exception,
"Unhandled exception while executing {Path}",
context.HttpContext.Request.Path);
context.Result = new ObjectResult(new
{
message = "An unexpected error occurred."
})
{
StatusCode = StatusCodes.Status500InternalServerError
};
context.ExceptionHandled = true;
}
}
Important Note About Exception Handling
Exception filters work for MVC/controller action exceptions.
For application-wide exception handling, ASP.NET Core middleware is usually better:
app.UseExceptionHandler("/error");
Use filters when the concern is controller-specific.
Use middleware when the concern applies to the whole HTTP pipeline.
Custom Header Filter Example
Suppose internal school APIs require a custom header.
public class RequireSchoolHeaderFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
if (!context.HttpContext.Request.Headers.ContainsKey("X-School-Code"))
{
context.Result = new BadRequestObjectResult(new
{
message = "X-School-Code header is required."
});
}
}
public void OnActionExecuted(ActionExecutedContext context)
{
}
}
Setting context.Result stops the action from running.
Filters vs Middleware
| Feature | Middleware | Filters |
|---|---|---|
| Scope | Entire request pipeline | MVC/controller pipeline |
| Runs before routing? | Can run before routing | No |
| Knows action details? | Usually no | Yes |
| Best for | Global HTTP concerns | Controller/action concerns |
| Examples | CORS, auth, static files, error handling | Action logging, result changes |
Common Mistakes
| Mistake | Better Approach |
|---|---|
| Putting business logic in filters | Keep business logic in services |
| Using filters for all error handling | Prefer middleware for global errors |
| Forgetting to register DI filters | Register with services |
| Logging sensitive request data | Log only safe context |
| Using filters when middleware is clearer | Pick the correct pipeline level |
Practice Task
Create an action filter:
- Name it
ApiRequestLogFilter. - Log action name before execution.
- Log status code after execution.
- Register it globally.
- Apply it only to
StudentsControlleras a second version.
Quick Recap
| Question | Answer |
|---|---|
| What are filters? | Code that runs around controller actions |
| Common filter for before/after action? | Action filter |
| Filter for action exceptions? | Exception filter |
| Global HTTP concerns? | Middleware is usually better |
| Controller-specific concerns? | Filters are useful |
Q: What are filters in ASP.NET Core?
Good Answer: "Filters are components that run before or after controller action execution. They handle cross-cutting concerns such as logging, authorization checks, result modification, and exception handling. Common filter types include authorization filters, action filters, result filters, exception filters, and resource filters. Filters can be registered globally, per controller, or per action. Middleware is better for application-wide pipeline concerns, while filters are better when action or controller context is needed."
Use ChatGPT, Claude, or Copilot to go deeper on ASP.NET Core Filters. Try these prompts:
"Explain filters vs middleware in simple terms.""Show me an action filter that logs execution time.""When should I use an exception filter?""What are cross-cutting concerns in ASP.NET Core?"
💡 Tip: After reading this article, paste your own code into AI and ask "What could go wrong here and why?" — fastest way to find edge cases and deepen understanding.