Middleware
Khái niệm
Middleware là các component nằm trong pipeline xử lý request/response. Mỗi middleware có thể:
- Xử lý request trước khi chuyển cho middleware tiếp theo
- Xử lý response sau khi các middleware trước đó đã xử lý
- Quyết định không chuyển request cho middleware tiếp theo (short-circuit)
Pipeline Execution Order
┌────────────────────────────────────────────────────────────────────┐
│ REQUEST PIPELINE │
├────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Logging │───▶│ Routing │───▶│ Auth │───▶│ Endpoint │ │
│ │ Middleware │ Middleware │ Middleware │ (Controller) │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ ▲ │ │
│ │ ▼ │
│ │ ┌──────────┐ ┌──────────┐ │
│ └───────────────────│ Response │◀───│ Error │ │
│ │ Middleware │ Middleware │ │
│ └──────────┘ └──────────┘ │
│ │
└────────────────────────────────────────────────────────────────────┘
Thứ tự quan trọng
- Exception Handling - Đầu tiên để bắt exceptions
- Security (CORS, Authentication, Authorization)
- Static Files - Nếu cần
- Routing - Xác định endpoint
- Endpoints - Controller/Action
- Custom Middleware
Cách viết Custom Middleware
1. Conventional Middleware Class
public class RequestTimingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<RequestTimingMiddleware> _logger;
public RequestTimingMiddleware(
RequestDelegate next,
ILogger<RequestTimingMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context)
{
var stopwatch = Stopwatch.StartNew();
// Before next middleware
_logger.LogInformation("Request started: {Path}", context.Request.Path);
await _next(context); // Call next middleware
// After next middleware
stopwatch.Stop();
_logger.LogInformation(
"Request completed in {ElapsedMs}ms",
stopwatch.ElapsedMilliseconds);
}
}
// Extension method để dễ đăng ký
public static class RequestTimingMiddlewareExtensions
{
public static IApplicationBuilder UseRequestTiming(
this IApplicationBuilder builder)
{
return builder.UseMiddleware<RequestTimingMiddleware>();
}
}
// Đăng ký trong Program.cs
var app = builder.Build();
app.UseRequestTiming();
2. Inline Middleware (Minimal API)
var app = builder.Build();
app.Use(async (context, next) =>
{
var stopwatch = Stopwatch.StartNew();
await next();
stopwatch.Stop();
Console.WriteLine($"Request took {stopwatch.ElapsedMilliseconds}ms");
});
app.MapGet("/", () => "Hello World");
app.Run();
3. Middleware with Dependencies
public class CustomMiddleware
{
private readonly RequestDelegate _next;
private readonly IConfiguration _config;
public CustomMiddleware(
RequestDelegate next,
IConfiguration config)
{
_next = next;
_config = config;
}
public async Task InvokeAsync(HttpContext context)
{
// Sử dụng injected dependencies
var timeout = _config.GetValue<int>("App:Timeout");
await _next(context);
}
}
Middleware vs Filters
Middleware
- Hoạt động trên toàn bộ request pipeline
- Thực thi trước khi routing xác định endpoint
- Phù hợp cho: Logging, Authentication, CORS, Error handling
Filters (MVC/Web API)
- Chỉ hoạt động cho MVC/Razor Pages actions
- Có access đến ActionContext
- Phù hợp cho: Model validation, Result caching, Exception handling cụ thể
Ví dụ so sánh
// Middleware - Cho toàn bộ app
app.Use(async (context, next) =>
{
// Log mọi request
await next();
});
// Filter - Chỉ cho MVC actions
public class ActionLogFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
// Log trước khi action chạy
}
public void OnActionExecuted(ActionExecutedContext context)
{
// Log sau khi action chạy
}
}