2.3 中间件 (Middleware) 2.3 中间件 (Middleware) in ASP.NET Core 在 ASP.NET Core 中,中间件是构建请求处理管道的核心组件。它就像一个链条,每个环节负责处理请求的特定方面,最终将请求传递给应用程序的终端点,并处理响应。 理解中间件对于构建高效、可维护和可扩展的 ASP.NET Core 应用程序至关重要。 2.3.1 什么是中间件? 中间件是组装到应用程序管道中以处理请求和响应的组件。每个中间件组件: 接收一个 对象,其中包含有关当前 HTTP 请求和响应的所有信息。 可以执行一些操作,例如: 检查请求头。 修改请求。 记录信息。 验证身份。 处理异常。 将请求传递给管道中的下一个中间件组件。
在 ASP.NET Core 中,中间件是构建请求处理管道的核心组件。它就像一个链条,每个环节负责处理请求的特定方面,最终将请求传递给应用程序的终端点,并处理响应。 理解中间件对于构建高效、可维护和可扩展的 ASP.NET Core 应用程序至关重要。
中间件是组装到应用程序管道中以处理请求和响应的组件。每个中间件组件:
接收一个 HttpContext 对象,其中包含有关当前 HTTP 请求和响应的所有信息。
可以执行一些操作,例如:
检查请求头。
修改请求。
记录信息。
验证身份。
处理异常。
将请求传递给管道中的下一个中间件组件。
可以选择短路管道,直接返回响应,不再执行后续中间件。
中间件通过 RequestDelegate 委托来表示,它定义了中间件组件的处理逻辑。
public delegate Task RequestDelegate(HttpContext context);
中间件组件按照它们在应用程序管道中注册的顺序执行。这种顺序非常重要,因为它决定了每个中间件组件处理请求和响应的时机。
请求管道:
请求进入应用程序时,会依次通过每个中间件组件。每个中间件组件都有机会检查和修改请求。
响应管道:
当请求到达管道的终端点(通常是一个控制器操作方法)并生成响应后,响应会沿着管道反向传播,再次通过每个中间件组件。每个中间件组件都有机会检查和修改响应。
以下 Mermaid 图展示了中间件管道的流程:
ASP.NET Core 提供了多种方式来配置中间件管道:
1. 使用 IApplicationBuilder 接口:
在 Startup.cs 文件的 Configure 方法中,可以使用 IApplicationBuilder 接口的扩展方法来添加中间件。这是最常用的方式。
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); // 添加认证中间件 app.UseAuthorization(); // 添加授权中间件 app.UseEndpoints(endpoints => { endpoints.MapRazorPages(); }); }
常用的 IApplicationBuilder 扩展方法:
UseMiddleware<T>(): 添加自定义中间件。
UseStaticFiles(): 启用静态文件服务。
UseRouting(): 启用路由。
UseAuthentication(): 启用身份验证。
UseAuthorization(): 启用授权。
UseExceptionHandler(): 处理未处理的异常。
UseHsts(): 启用 HTTP Strict Transport Security (HSTS)。
UseHttpsRedirection(): 将 HTTP 请求重定向到 HTTPS。
UseDeveloperExceptionPage(): 在开发环境中显示详细的异常信息。
UseEndpoints(): 配置路由终结点。
2. 使用 ConfigureServices 方法:
可以在 Startup.cs 文件的 ConfigureServices 方法中注册中间件所需的依赖项。
3. 使用 Endpoint Routing:
ASP.NET Core 3.0 及更高版本引入了 Endpoint Routing,它允许将中间件与特定的终结点关联起来。 这使得可以更精细地控制哪些中间件组件应用于哪些请求。
可以创建自定义中间件来处理应用程序的特定需求。 创建自定义中间件通常涉及以下步骤:
1. 创建一个类,实现中间件逻辑。
该类通常需要:
一个构造函数,接收 RequestDelegate 作为参数,表示管道中的下一个中间件。
一个 Invoke 或 InvokeAsync 方法,接收 HttpContext 作为参数,并包含中间件的处理逻辑。
public class MyCustomMiddleware { private readonly RequestDelegate _next; private readonly ILogger<MyCustomMiddleware> _logger; public MyCustomMiddleware(RequestDelegate next, ILogger<MyCustomMiddleware> logger) { _next = next ?? throw new ArgumentNullException(nameof(next)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } public async Task InvokeAsync(HttpContext context) { _logger.LogInformation("MyCustomMiddleware: Request received."); // 在调用下一个中间件之前执行一些操作 context.Items["CustomKey"] = "Custom Value"; // 调用管道中的下一个中间件 await _next(context); // 在调用下一个中间件之后执行一些操作 _logger.LogInformation("MyCustomMiddleware: Response sent."); } }
2. 注册中间件。
在 Startup.cs 文件的 Configure 方法中,使用 UseMiddleware<T>() 扩展方法注册中间件。
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { // ... 其他配置 ... app.UseMiddleware<MyCustomMiddleware>(); // ... 其他配置 ... }
3. 创建中间件扩展方法 (可选,但推荐)。
创建一个扩展方法可以使注册中间件的代码更简洁易读。
public static class MyCustomMiddlewareExtensions { public static IApplicationBuilder UseMyCustomMiddleware(this IApplicationBuilder builder) { return builder.UseMiddleware<MyCustomMiddleware>(); } }
然后,在 Configure 方法中,可以使用扩展方法来注册中间件:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { // ... 其他配置 ... app.UseMyCustomMiddleware(); // ... 其他配置 ... }
中间件的顺序至关重要,因为它决定了每个中间件组件处理请求和响应的顺序。
示例:
考虑以下中间件顺序:
UseAuthentication()
UseAuthorization()
UseEndpoints()
在这个顺序中,身份验证中间件首先验证用户的身份,然后授权中间件确定用户是否有权访问请求的资源。最后,终结点路由中间件将请求路由到相应的控制器操作方法。
如果身份验证中间件在授权中间件之后执行,那么授权中间件将无法确定用户是否已通过身份验证,从而导致授权失败。
最佳实践:
通常,应将身份验证和授权中间件放在路由中间件之前。
静态文件中间件应放在路由中间件之前,以避免将静态文件请求路由到控制器操作方法。
异常处理中间件应放在管道的早期,以便它可以捕获管道中发生的任何异常。
1. 一个简单的记录请求信息的中间件:
public class RequestLoggingMiddleware { private readonly RequestDelegate _next; private readonly ILogger<RequestLoggingMiddleware> _logger; public RequestLoggingMiddleware(RequestDelegate next, ILogger<RequestLoggingMiddleware> logger) { _next = next; _logger = logger; } public async Task InvokeAsync(HttpContext context) { _logger.LogInformation($"Request: {context.Request.Method} {context.Request.Path}"); await _next(context); } } public static class RequestLoggingMiddlewareExtensions { public static IApplicationBuilder UseRequestLogging(this IApplicationBuilder builder) { return builder.UseMiddleware<RequestLoggingMiddleware>(); } }
在 Startup.cs 中注册:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseRequestLogging(); // ... 其他中间件 ... }
2. 一个处理异常的中间件:
public class ExceptionHandlingMiddleware { private readonly RequestDelegate _next; private readonly ILogger<ExceptionHandlingMiddleware> _logger; public ExceptionHandlingMiddleware(RequestDelegate next, ILogger<ExceptionHandlingMiddleware> logger) { _next = next; _logger = logger; } public async Task InvokeAsync(HttpContext context) { try { await _next(context); } catch (Exception ex) { _logger.LogError(ex, "An unhandled exception occurred."); context.Response.StatusCode = 500; await context.Response.WriteAsync("An error occurred."); } } } public static class ExceptionHandlingMiddlewareExtensions { public static IApplicationBuilder UseExceptionHandling(this IApplicationBuilder builder) { return builder.UseMiddleware<ExceptionHandlingMiddleware>(); } }
在 Startup.cs 中注册,并确保它在管道的早期:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseExceptionHandling(); // ... 其他中间件 ... }
中间件是 ASP.NET Core 中构建请求处理管道的关键组件。通过理解中间件的工作原理和配置方式,可以构建高效、可维护和可扩展的应用程序。 记住中间件的顺序至关重要,并根据应用程序的特定需求创建自定义中间件。 通过合理使用中间件,可以显著提高应用程序的性能、安全性和可维护性。