Filters
Các loại Filter
Filters cho phép chạy code tại các điểm cụ thể trong pipeline execution của MVC.
┌─────────────────────────────────────────────────────────────────────┐
│ MVC REQUEST PIPELINE │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 1. Authorization Filter │
│ ↓ │
│ 2. Resource Filter (OnExecuting) │
│ ↓ │
│ 3. Model Binding │
│ ↓ │
│ 4. Action Filter (OnExecuting) │
│ ↓ │
│ 5. Action executes │
│ ↓ │
│ 6. Action Filter (OnExecuted) │
│ ↓ │
│ 7. Result Filter (OnExecuting) │
│ ↓ │
│ 8. Result executes │
│ ↓ │
│ 9. Result Filter (OnExecuted) │
│ ↓ │
│ 10. Resource Filter (OnExecuted) │
│ │
└─────────────────────────────────────────────────────────────────────┘
1. Authorization Filter
public class CustomAuthorizationFilter : IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
var user = context.HttpContext.User;
if (!user.Identity.IsAuthenticated)
{
context.Result = new UnauthorizedResult();
}
}
}
// Sử dụng
[ServiceFilter(typeof(CustomAuthorizationFilter))]
public class ProductsController : ControllerBase { }
2. Resource Filter
public class TrackRequestFilter : IAsyncResourceFilter
{
private readonly ILogger<TrackRequestFilter> _logger;
public TrackRequestFilter(ILogger<TrackRequestFilter> logger)
{
_logger = logger;
}
public async Task OnResourceExecutingAsync(ResourceExecutingContext context)
{
_logger.LogInformation("Resource executing");
// Thực thi trước khi resource (controller) được gọi
context.HttpContext.Items["StartTime"] = DateTime.UtcNow;
}
public async Task OnResourceExecutedAsync(ResourceExecutedContext context)
{
var startTime = (DateTime)context.HttpContext.Items["StartTime"];
_logger.LogInformation($"Resource executed in {(DateTime.UtcNow - startTime).TotalMilliseconds}ms");
}
}
3. Action Filter
public class LogActionFilter : IActionFilter
{
private readonly ILogger<LogActionFilter> _logger;
public LogActionFilter(ILogger<LogActionFilter> logger)
{
_logger = logger;
}
public void OnActionExecuting(ActionExecutingContext context)
{
_logger.LogInformation("Action executing: {Controller}.{Action}",
context.Controller.GetType().Name,
context.ActionDescriptor.Name);
}
public void OnActionExecuted(ActionExecutedContext context)
{
_logger.LogInformation("Action executed");
}
}
4. Exception Filter
public class GlobalExceptionFilter : IExceptionFilter
{
private readonly ILogger<GlobalExceptionFilter> _logger;
public GlobalExceptionFilter(ILogger<GlobalExceptionFilter> logger)
{
_logger = logger;
}
public void OnException(ExceptionContext context)
{
_logger.LogError(context.Exception, "Unhandled exception");
var result = new
{
error = "An error occurred",
message = context.Exception.Message,
traceId = context.HttpContext.TraceIdentifier
};
context.Result = new JsonResult(result)
{
StatusCode = 500
};
context.ExceptionHandled = true;
}
}
5. Result Filter
public class CacheResultFilter : IResultFilter
{
public void OnResultExecuting(ResultExecutingContext context)
{
if (!context.HttpContext.Response.HasStarted)
{
context.HttpContext.Response.Headers["Cache-Control"] = "no-cache";
}
}
public void OnResultExecuted(ResultExecutedContext context)
{
// Post-processing
}
}
Filter Types Comparison
| Filter Type | Implements | Runs | Use Case |
|---|---|---|---|
| Authorization | IAuthorizationFilter | Đầu tiên | Check authentication/authorization |
| Resource | IResourceFilter | Trước & sau model binding | Caching, performance tracking |
| Action | IActionFilter | Trước & sau action | Logging, validation |
| Exception | IExceptionFilter | Khi exception xảy ra | Error handling |
| Result | IResultFilter | Trước & sau result execution | Output formatting, caching |
Filters vs Middleware
Filters
- ✅ Chỉ áp dụng cho MVC/Razor Pages
- ✅ Có access đến
ActionContext(model binding results, etc.) - ✅ Có thể bind services từ DI
- ✅ Thực thi sau khi route đã được xác định
Middleware
- ✅ Áp dụng cho toàn bộ pipeline (bao gồm static files)
- ✅ Thực thi trước khi routing xác định endpoint
- ✅ Phù hợp cho cross-cutting concerns không liên quan đến MVC
Khi nào dùng?
// Middleware - Cho toàn bộ app
app.Use(async (context, next) =>
{
// Log mọi request
await next();
});
// Filter - Cho MVC actions cụ thể
[ServiceFilter(typeof(MyActionFilter))]
public class ProductsController : ControllerBase { }
Đăng ký Filters
1. Global
builder.Services.AddControllersWithViews()
.AddMvcOptions(options =>
{
options.Filters.Add(new GlobalExceptionFilter());
});
2. Controller/Action Level
[ControllerLevelFilter]
public class ProductsController : ControllerBase
{
[ActionLevelFilter]
public IActionResult Get() { }
}
3. Service Filter
// Đăng ký trong DI
builder.Services.AddScoped<MyFilter>();
// Sử dụng
[ServiceFilter(typeof(MyFilter))]
public IActionResult Get() { }
4. Type Filter
// Không cần đăng ký trong DI
[TypeFilter(typeof(MyFilter))]
public IActionResult Get() { }