在ASP.NET Core应用中,中间件管道是一系列按顺序排列的请求委托,每个中间件都可以对请求进行处理,也能决定是否将请求传递给下一个中间件。理解中间件管道的创建和自定义方法,是进阶ASP.NET Core开发的重要基础。

中间件管道的基础原理
ASP.NET Core的请求处理流程本质是一个中间件管道,当请求进入应用时,会按照中间件的注册顺序依次执行,每个中间件处理完成后可以选择传递给下一个中间件,也可以直接返回响应,这个过程被称为管道短路。中间件的执行顺序和注册顺序一致,响应的处理顺序则和注册顺序相反,形成类似洋葱模型的执行结构。
自定义中间件的基本实现方式
方式一:基于约定类创建中间件
ASP.NET Core支持通过符合约定的类来定义中间件,这类中间件需要包含构造函数和一个InvokeAsync方法,构造函数可以接收下一个中间件的请求委托,InvokeAsync方法接收HttpContext参数用于处理请求。
下面是一个记录请求执行时间的中间件示例:
using Microsoft.AspNetCore.Http;
using System.Diagnostics;
using System.Threading.Tasks;
public class RequestTimeMiddleware
{
private readonly RequestDelegate _next;
// 构造函数接收下一个中间件的委托
public RequestTimeMiddleware(RequestDelegate next)
{
_next = next;
}
// 处理请求的核心方法
public async Task InvokeAsync(HttpContext context)
{
var stopwatch = Stopwatch.StartNew();
// 执行下一个中间件
await _next(context);
stopwatch.Stop();
// 在响应头中添加请求处理时间
context.Response.Headers.Add("X-Request-Time", stopwatch.ElapsedMilliseconds.ToString());
}
}
方式二:使用内联中间件委托
除了定义独立的中间件类,还可以通过app.Use方法直接注册内联的中间件委托,这种方式适合逻辑比较简单的中间件场景。
下面是内联中间件的使用示例:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// 注册内联中间件
app.Use(async (context, next) =>
{
// 请求处理前逻辑
context.Items["RequestStart"] = DateTime.Now;
// 传递给下一个中间件
await next();
// 响应处理后逻辑
var startTime = (DateTime)context.Items["RequestStart"];
var elapsed = DateTime.Now - startTime;
Console.WriteLine($"请求处理耗时:{elapsed.TotalMilliseconds}毫秒");
});
app.MapGet("/", () => "Hello World!");
app.Run();
将自定义中间件注册到管道中
定义好中间件之后,需要将其添加到请求管道中才能生效。对于基于约定类的中间件,可以通过app.UseMiddleware<中间件类名>()方法注册,也可以先封装扩展方法方便复用。
下面是中间件扩展方法的实现和注册示例:
using Microsoft.AspNetCore.Builder;
public static class RequestTimeMiddlewareExtensions
{
// 封装中间件注册的扩展方法
public static IApplicationBuilder UseRequestTimeMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<RequestTimeMiddleware>();
}
}
在Program.cs中注册中间件:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// 注册自定义中间件,注意顺序会影响执行流程
app.UseRequestTimeMiddleware();
app.Use(async (context, next) =>
{
Console.WriteLine("第二个中间件开始处理请求");
await next();
Console.WriteLine("第二个中间件处理响应完成");
});
app.MapGet("/", () => "Hello World!");
app.Run();
中间件管道进阶知识点
中间件短路机制
如果某个中间件不调用next委托,那么管道会在该中间件处短路,后续的中间件都不会执行,直接返回当前中间件的响应。这种机制适合做请求校验、鉴权等场景,比如校验不通过时直接返回错误响应。
短路中间件示例:
app.Use(async (context, next) =>
{
// 校验请求头中是否包含授权信息
if (!context.Request.Headers.ContainsKey("Authorization"))
{
context.Response.StatusCode = 401;
await context.Response.WriteAsync("未授权访问");
// 不调用next,直接短路管道
return;
}
// 校验通过则传递给下一个中间件
await next();
});
分支管道的使用
ASP.NET Core提供了app.Map和app.MapWhen方法,可以根据请求的条件创建分支管道,不同分支可以注册不同的中间件,不会影响主管道的执行流程。
分支管道示例:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// 主管道中间件
app.Use(async (context, next) =>
{
Console.WriteLine("主管道中间件执行");
await next();
});
// 路径为/api的分支管道
app.Map("/api", apiApp =>
{
apiApp.Use(async (context, next) =>
{
Console.WriteLine("API分支管道中间件执行");
await next();
});
apiApp.MapGet("/", () => "API接口响应");
});
app.MapGet("/", () => "首页响应");
app.Run();
自定义中间件的注意事项
- 中间件的构造函数中不要依赖Scoped生命周期的服务,因为中间件的生命周期是单例的,如果需要使用Scoped服务,可以在InvokeAsync方法的参数中注入,ASP.NET Core会自动解析对应作用域的服务实例。
- 中间件的注册顺序非常重要,会影响请求处理的逻辑,一般把异常处理中间件放在最前面,然后是静态文件中间件、路由中间件、鉴权中间件等,最后是终结点中间件。
- 如果中间件需要处理响应体,要注意响应体只能写入一次,避免多次写入导致异常,同时修改响应头要在响应体写入之前操作。
总结:自定义中间件的核心是理解请求委托的传递逻辑,通过合理的中间件注册顺序和短路机制,可以灵活实现各种请求处理需求,构建符合业务场景的请求处理管道。
ASP.NET_Core中间件中间件管道C#修改时间:2026-06-28 12:42:34