1、中间件管道简介
在 C# ASP.NET Core 中,中间件管道是处理 HTTP 请求和响应的核心机制,通过将多个中间件按顺序串联成一个处理流程,实现灵活的请求处理和业务逻辑组合。以下是其核心要点:
1. 中间件管道的基本概念
2. 管道的工作模式:1-n 然后 n-1
3. 如何配置中间件管道
在 Startup.Configure 方法中通过 IApplicationBuilder 注册中间件,常用方法包括:
4. 中间件的关键特性
短路机制:中间件可选择不调用 next() ,直接返回响应(如身份验证失败时)。
依赖注入:可通过构造函数注入服务(如数据库上下文) 。
可重用性:中间件可封装为类,通过UseMiddleware<T>()注册。
在使用ASP. NET时,若要修改请求头,则要在返回响应之前修改。
5. 典型应用场景
内置中间件:ASP.NET Core 提供多种内置中间件,如静态文件处理、MVC 路由、错误页面等。
自定义逻辑:例如记录请求日志、跨域处理(CORS)、缓存等 。
跨平台支持:借助 .NET Core,中间件管道可在 Windows、Linux、macOS 上运行 。
示例代码(自定义中间件)
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class LoggingMiddleware { private readonly RequestDelegate _next; public LoggingMiddleware(RequestDelegate next) => _next = next;
public async Task InvokeAsync(HttpContext context) { Console.WriteLine($"请求路径:{context.Request.Path}"); await _next(context); Console.WriteLine($"响应状态码:{context.Response.StatusCode}"); } }
app.UseMiddleware<LoggingMiddleware>();
|
通过中间件管道,开发者可以灵活构建高效、模块化的 Web 应用,满足不同场景的需求。更多实现细节可参考 ASP.NET Core 文档。
2、中间件管道实现-USE(最小API)
app.Use通常实现常规中间件组件和短路中间件组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| var builder = WebApplication.CreateBuilder(args); var app = builder.Build();
app.Use(async (HttpContext context, RequestDelegate next) => { await context.Response.WriteAsync("Middleware #1: Before calling next\r\n"); await next(context); await context.Response.WriteAsync("Middleware #1: After calling next\r\n"); });
app.Use(async (HttpContext context, RequestDelegate next) => { await context.Response.WriteAsync("Middleware #2: Before calling next\r\n"); await next(context); await context.Response.WriteAsync("Middleware #2: After calling next\r\n"); });
app.Use(async (HttpContext context, RequestDelegate next) => { await context.Response.WriteAsync("Middleware #3: Before calling next\r\n"); await next(context); await context.Response.WriteAsync("Middleware #3: After calling next\r\n"); });
app.Run();
|

3、短路
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| var builder = WebApplication.CreateBuilder(args); var app = builder.Build();
app.Use(async (HttpContext context, RequestDelegate next) => { await context.Response.WriteAsync("Middleware #1: Before calling next\r\n"); await next(context); await context.Response.WriteAsync("Middleware #1: After calling next\r\n"); });
app.Use(async (HttpContext context, RequestDelegate next) => { await context.Response.WriteAsync("Middleware #2: Before calling next\r\n"); await next(context); await context.Response.WriteAsync("Middleware #2: After calling next\r\n"); });
app.Use(async (HttpContext context, RequestDelegate next) => { await context.Response.WriteAsync("Middleware #3: Before calling next\r\n"); await next(context); await context.Response.WriteAsync("Middleware #3: After calling next\r\n"); });
app.Run();
|

4、中间件管道实现-RUN(最小API)
app.RUN不传递context到下一个请求委托,仅实现短路中间件组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| var builder = WebApplication.CreateBuilder(args); var app = builder.Build();
app.Use(async (HttpContext context, RequestDelegate next) => { await context.Response.WriteAsync("Middleware #1: Before calling next\r\n"); await next(context); await context.Response.WriteAsync("Middleware #1: After calling next\r\n"); });
app.Run(async (context) => { await context.Response.WriteAsync("Middleware #2: Processed.\r\n"); });
app.Use(async (HttpContext context, RequestDelegate next) => { await context.Response.WriteAsync("Middleware #3: Before calling next\r\n"); await next(context); await context.Response.WriteAsync("Middleware #3: After calling next\r\n"); }); app.Run();
|

5、中间件管道创建分支-MAP

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| var builder = WebApplication.CreateBuilder(args); var app = builder.Build();
app.Use(async (HttpContext context, RequestDelegate next) => { await context.Response.WriteAsync("Middleware #1: Before calling next\r\n"); await next(context); await context.Response.WriteAsync("Middleware #1: After calling next\r\n"); });
app.Map("/employees", (appBuilder) => { appBuilder.Use(async (HttpContext context, RequestDelegate next) => { await context.Response.WriteAsync("Middleware #5: Before calling next\r\n"); await next(context); await context.Response.WriteAsync("Middleware #5: After calling next\r\n"); });
appBuilder.Use(async (HttpContext context, RequestDelegate next) => { await context.Response.WriteAsync("Middleware #6: Before calling next\r\n"); await next(context); await context.Response.WriteAsync("Middleware #6: After calling next\r\n"); }); });
app.Use(async (context, next) => { await context.Response.WriteAsync("Middleware #2: Before calling next\r\n"); await next(context); await context.Response.WriteAsync("Middleware #2: After calling next\r\n"); });
app.Use(async (HttpContext context, RequestDelegate next) => { await context.Response.WriteAsync("Middleware #3: Before calling next\r\n"); await next(context); await context.Response.WriteAsync("Middleware #3: After calling next\r\n"); });
app.Run();
|
# 6、中间件管道创建分支-MapWhen
MapWhen可以通过访问Http上下文对象,从而在复杂条件下创建中间件管道分支。当MapWhen中的结果为真时将从分支运行,否则在主流程中运行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| var builder = WebApplication.CreateBuilder(args); var app = builder.Build();
app.Use(async (HttpContext context, RequestDelegate next) => { await context.Response.WriteAsync("Middleware #1: Before calling next\r\n"); await next(context); await context.Response.WriteAsync("Middleware #1: After calling next\r\n"); });
app.MapWhen((context) => { return context.Request.Path.StartsWithSegments("/employees") && context.Request.Query.ContainsKey("id"); }, (appBuilder) => { appBuilder.Use(async (HttpContext context, RequestDelegate next) => { await context.Response.WriteAsync("Middleware #5: Before calling next\r\n"); await next(context); await context.Response.WriteAsync("Middleware #5: After calling next\r\n"); });
appBuilder.Use(async (HttpContext context, RequestDelegate next) => { await context.Response.WriteAsync("Middleware #6: Before calling next\r\n"); await next(context); await context.Response.WriteAsync("Middleware #6: After calling next\r\n"); }); });
app.Use(async (context, next) => { await context.Response.WriteAsync("Middleware #2: Before calling next\r\n"); await next(context); await context.Response.WriteAsync("Middleware #2: After calling next\r\n"); });
app.Use(async (HttpContext context, RequestDelegate next) => { await context.Response.WriteAsync("Middleware #3: Before calling next\r\n"); await next(context); await context.Response.WriteAsync("Middleware #3: After calling next\r\n"); });
app.Run();
|



7、运行分支后回到主流程-UseWhen
UseWhen与MapWhen类似,但当分支运行完后,会接着回到主流程中继续运行,直到运行到最终端点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Use(async (HttpContext context, RequestDelegate next) => { await context.Response.WriteAsync("Middleware #1: Before calling next\r\n"); await next(context); await context.Response.WriteAsync("Middleware #1: After calling next\r\n"); });
app.UseWhen((context) => { return context.Request.Path.StartsWithSegments("/employees") && context.Request.Query.ContainsKey("id"); }, (appBuilder) => { appBuilder.Use(async (HttpContext context, RequestDelegate next) => { await context.Response.WriteAsync("Middleware #5: Before calling next\r\n"); await next(context); await context.Response.WriteAsync("Middleware #5: After calling next\r\n"); });
appBuilder.Use(async (HttpContext context, RequestDelegate next) => { await context.Response.WriteAsync("Middleware #6: Before calling next\r\n"); await next(context); await context.Response.WriteAsync("Middleware #6: After calling next\r\n");
}); });
app.Use(async (context, next) => { await context.Response.WriteAsync("Middleware #2: Before calling next\r\n"); await next(context); await context.Response.WriteAsync("Middleware #2: After calling next\r\n"); });
app.Use(async (HttpContext context, RequestDelegate next) => { await context.Response.WriteAsync("Middleware #3: Before calling next\r\n"); await next(context); await context.Response.WriteAsync("Middleware #3: After calling next\r\n");
});
app.Run();
|


8、横切-类似于Aspect
使用自定义中间件
1.MyCustomExceptionHandler.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| namespace WebApp.MiddleComponents { public class MyCustomExceptionHandler : IMiddleware { public async Task InvokeAsync(HttpContext context, RequestDelegate next) { try { context.Response.ContentType = "text/html"; await next(context); } catch (Exception ex) { await context.Response.WriteAsync("<h2>Error:</h2>"); await context.Response.WriteAsync($"<p>{ex.Message}</p>"); } } } }
|
2.MyCustomMiddleware.cs
1 2 3 4 5 6 7 8 9 10 11 12 13
| namespace WebApp.MiddleComponents { public class MyCustomMiddleware : IMiddleware { public async Task InvokeAsync(HttpContext context, RequestDelegate next) {
await context.Response.WriteAsync("<p>My custom middleware: Before calling next</p>"); await next(context); await context.Response.WriteAsync("<p>My custom middleware: After calling next</p>"); } } }
|
3.Program.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| using WebApp.MiddleComponents;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddTransient<MyCustomMiddleware>(); builder.Services.AddTransient<MyCustomExceptionHandler>();
var app = builder.Build();
app.UseMiddleware<MyCustomExceptionHandler>();
app.Use(async (HttpContext context, RequestDelegate next) => { context.Response.ContentType = "text/html"; await context.Response.WriteAsync("<p>Middleware #1: Before calling next</p>"); await next(context); await context.Response.WriteAsync("<p>Middleware #1: After calling next</p>"); });
app.UseMiddleware<MyCustomMiddleware>();
app.Use(async (context, next) => { throw new ApplicationException("Exception for testing."); await context.Response.WriteAsync("<p>Middleware #2: Before calling next</p>"); await next(context); await context.Response.WriteAsync("<p>Middleware #2: After calling next</p>"); });
app.Use(async (HttpContext context, RequestDelegate next) => { await context.Response.WriteAsync("<p>Middleware #3: Before calling next</p>"); await next(context); await context.Response.WriteAsync("<p>Middleware #3: After calling next</p>"); });
app.Run();
|
