Both ActionFilter and Middleware are powerful mechanisms in ASP.NET Core used to handle cross-cutting concerns, but they operate at different levels of the request pipeline and serve distinct purposes.
1. Basic Concept
| Aspect |
Middleware |
ActionFilter |
| Definition |
Handles incoming requests and outgoing responses at the application level. |
Handles logic before and after controller actions at the controller/action level. |
| Pipeline |
Executes before the request reaches routing and MVC. |
Executes after routing but before/after controller actions. |
| Scope |
Applies to the entire application. |
Applies to specific controllers or actions. |
2. Execution Flow
| Aspect |
Middleware |
ActionFilter |
| When It Runs |
Runs before routing, or globally throughout the pipeline. |
Runs before and after controller actions. |
| Control Flow |
Uses await next() to continue the pipeline. |
Uses OnActionExecuting and OnActionExecuted methods. |
| Execution Context |
Has access to the HttpContext (global request/response). |
Has access to the ActionContext (controller/action details). |
3. Use Cases
| Middleware |
ActionFilter |
| Global logging of requests and responses. |
Logging at the controller/action level. |
| Authentication/Authorization across the app. |
Model validation for specific actions. |
| Global exception handling (Error handling). |
Input validation and action-specific security checks. |
| Response compression, caching, CORS policies. |
Custom logic before/after an action executes. |
| Routing, static file serving, and session management. |
Result filtering or modifying the action result. |
4. Implementation
Middleware Example
public class CustomMiddleware
{
private readonly RequestDelegate _next;
public CustomMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
// Pre-processing logic
Console.WriteLine("Middleware: Before next");
await _next(context); // Continue to the next middleware
// Post-processing logic
Console.WriteLine("Middleware: After next");
}
}
// Register Middleware in Program.cs or Startup.cs
app.UseMiddleware<CustomMiddleware>();
ActionFilter Example
public class CustomActionFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
// Logic before the action executes
Console.WriteLine("ActionFilter: Before action execution");
}
public override void OnActionExecuted(ActionExecutedContext context)
{
// Logic after the action executes
Console.WriteLine("ActionFilter: After action execution");
}
}
// Apply to a specific controller or action
[CustomActionFilter]
public IActionResult MyAction()
{
return Ok("Hello World");
}
5. Key Differences
| Feature |
Middleware |
ActionFilter |
| Level |
Application-wide. |
Controller or action-specific. |
| Execution Point |
Runs early in the pipeline, even before routing. |
Runs after routing but before/after actions. |
| Context Access |
Accesses HttpContext (global request/response data). |
Accesses ActionContext (controller/action data). |
| Flexibility |
Better for cross-cutting concerns (logging, auth). |
Better for action-specific logic (validation). |
| Error Handling |
Handles global errors (exception middleware). |
Handles action-specific errors. |
| Usage Scope |
Ideal for app-wide concerns. |
Ideal for controller/action concerns. |
6. When to Use?
- Use Middleware when:
- You need to handle global concerns like logging, authentication, authorization, error handling, or CORS.
- You need to manipulate the request/response pipeline before it reaches the routing system.
- Use ActionFilter when:
- You need logic tied specifically to controller actions (e.g., model validation, custom authorization).
- You want to manipulate action inputs or results.
7. Summary
| Aspect |
Middleware |
ActionFilter |
| Scope |
Global, application-wide. |
Specific to controllers/actions. |
| Execution Timing |
Before routing and controller execution. |
Before and after controller actions. |
| Best for |
Cross-cutting concerns (auth, logging, errors). |
Action-specific logic (validation, logging). |
| Context Access |
HttpContext (global request data). |
ActionContext (action-specific data). |
| Pipeline Control |
Uses await next() to continue. |
Uses OnActionExecuting/OnActionExecuted. |
In summary, Middleware is suited for global application behavior, while ActionFilter is best for controller/action-specific logic.