一、什么是ASP.NET Core中间件
中间件是ASP.NET Core管道中的核心组件,可以把它想象成洋葱的一层层皮。每个请求都会依次穿过这些中间件层,每个中间件都可以对请求进行处理或者修改。比如我们常见的静态文件处理、身份验证、路由等功能,都是通过中间件实现的。
想象一下你去银行办业务的场景:进门先取号(路由中间件),然后保安检查证件(认证中间件),柜台办理业务(业务逻辑中间件),最后拿到回执(响应处理中间件)。这就是中间件的工作方式。
二、自定义中间件开发实战
让我们通过一个实际的例子来创建一个简单的日志记录中间件。这个中间件会记录每个请求的进入和离开时间。
// 技术栈:ASP.NET Core 6.0
public class RequestLoggerMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<RequestLoggerMiddleware> _logger;
// 构造函数注入ILogger服务
public RequestLoggerMiddleware(
RequestDelegate next,
ILogger<RequestLoggerMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context)
{
// 请求进入时记录
var startTime = DateTime.UtcNow;
_logger.LogInformation($"Request started: {context.Request.Path} at {startTime}");
// 调用管道中的下一个中间件
await _next(context);
// 请求完成时记录
var endTime = DateTime.UtcNow;
var duration = endTime - startTime;
_logger.LogInformation($"Request completed: {context.Request.Path} in {duration.TotalMilliseconds}ms");
}
}
// 扩展方法,方便在Startup中使用
public static class RequestLoggerMiddlewareExtensions
{
public static IApplicationBuilder UseRequestLogger(this IApplicationBuilder builder)
{
return builder.UseMiddleware<RequestLoggerMiddleware>();
}
}
在Startup.cs中使用这个中间件:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// 其他中间件...
app.UseRequestLogger(); // 添加我们的日志中间件
// 其他中间件...
}
这个中间件现在可以记录每个请求的耗时,对于性能监控非常有用。
三、中间件的执行顺序
中间件的执行顺序非常重要,就像安检必须在登机前完成一样。ASP.NET Core中间件是按照添加到管道的顺序执行的,但响应时是反向的。
让我们看一个更复杂的例子:
public void Configure(IApplicationBuilder app)
{
// 异常处理应该放在最前面
app.UseExceptionHandler("/Error");
// HTTPS重定向
app.UseHttpsRedirection();
// 静态文件中间件
app.UseStaticFiles();
// 路由中间件
app.UseRouting();
// 认证中间件
app.UseAuthentication();
app.UseAuthorization();
// 我们的自定义日志中间件
app.UseRequestLogger();
// 终结点中间件
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
执行顺序说明:
- 请求进入时:从上往下执行
- 响应返回时:从下往上执行
如果把日志中间件放在最前面,它将无法记录后续中间件处理的时间。如果把认证中间件放在路由后面,路由可能无法获取用户信息。
四、中间件中的依赖注入
中间件支持完整的依赖注入,这是ASP.NET Core的一大优势。我们来看一个更复杂的例子,它使用到了多个注入的服务。
public class PerformanceMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<PerformanceMiddleware> _logger;
private readonly IMemoryCache _cache;
private readonly IConfiguration _config;
public PerformanceMiddleware(
RequestDelegate next,
ILogger<PerformanceMiddleware> logger,
IMemoryCache cache,
IConfiguration config)
{
_next = next;
_logger = logger;
_cache = cache;
_config = config;
}
public async Task InvokeAsync(HttpContext context)
{
var watch = Stopwatch.StartNew();
// 检查配置是否启用性能监控
var enabled = _config.GetValue<bool>("Performance:Enabled");
if (!enabled)
{
await _next(context);
return;
}
// 调用下一个中间件
await _next(context);
watch.Stop();
// 如果响应时间超过阈值,记录警告
var threshold = _config.GetValue<int>("Performance:ThresholdMs");
if (watch.ElapsedMilliseconds > threshold)
{
_logger.LogWarning($"慢请求: {context.Request.Path} 耗时 {watch.ElapsedMilliseconds}ms");
// 将慢请求信息缓存起来供后续分析
var slowRequests = _cache.GetOrCreate("SlowRequests", entry =>
{
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5);
return new ConcurrentBag<SlowRequestInfo>();
});
slowRequests?.Add(new SlowRequestInfo
{
Path = context.Request.Path,
Duration = watch.ElapsedMilliseconds,
Timestamp = DateTime.UtcNow
});
}
}
}
public class SlowRequestInfo
{
public string Path { get; set; }
public long Duration { get; set; }
public DateTime Timestamp { get; set; }
}
这个中间件展示了如何注入和使用多个服务:
- ILogger用于记录日志
- IMemoryCache用于缓存慢请求信息
- IConfiguration用于读取配置
五、高级中间件模式
有时候我们需要根据条件动态决定是否使用某个中间件。ASP.NET Core提供了Map和MapWhen等方法来实现这种模式。
public void Configure(IApplicationBuilder app)
{
// 基本中间件...
// 只为/api开头的路径添加性能监控
app.MapWhen(
context => context.Request.Path.StartsWithSegments("/api"),
apiBranch =>
{
apiBranch.UseMiddleware<PerformanceMiddleware>();
apiBranch.UseRouting();
apiBranch.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
});
// 其他路径走常规处理
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
MapWhen让我们可以基于请求的某些特征(如路径、请求头等)来有条件地应用中间件。这在微服务架构中特别有用,比如只为特定服务启用某些功能。
六、实际应用场景与最佳实践
应用场景:
- 请求/响应日志记录
- 性能监控
- 异常处理
- 认证授权
- 缓存控制
- API版本控制
- 请求限流
技术优缺点:
- 优点:
- 高度模块化,每个中间件只关注单一职责
- 灵活的管道配置
- 支持依赖注入
- 性能高效
- 缺点:
- 执行顺序容易出错
- 过度使用会导致管道复杂
- 优点:
注意事项:
- 异常处理中间件应该放在管道的最前面
- 静态文件中间件应该在路由中间件之前
- 认证中间件应该在路由之后、终结点之前
- 避免在中间件中做耗时操作,会影响整体性能
总结: ASP.NET Core中间件是一个非常强大的功能,理解它的工作原理和最佳实践对于构建高效、可维护的Web应用至关重要。通过自定义中间件,我们可以轻松实现各种横切关注点,保持业务代码的简洁性。记住中间件的执行顺序是关键,合理的依赖注入使用能让中间件更加强大和灵活。
评论