当前位置: 首页 > news >正文

深入理解 ASP.NET Core 中的 UseRouting 与 UseEndpoints

一、从请求管道说起

ASP.NET Core 的核心是一条中间件管道(Middleware Pipeline)。每一个 HTTP 请求都会沿着这条管道依次经过各个 中间件 ,最终产生响应。

HTTP 请求

异常处理
UseExceptionHandler

静态文件
UseStaticFiles

🔵 UseRouting
路由匹配

授权
UseAuthorization

🟣 UseEndpoints
端点执行

HTTP 响应

UseRoutingUseEndpoints 是这条管道中最关键的两个环节,但很多开发者对它们的分工并不清晰——它们看起来"都跟路由有关",实际上职责截然不同。


二、路由系统的两阶段设计

ASP.NET Core 3.0 引入了端点路由(Endpoint Routing),将路由解析拆分为两个独立阶段:

⚡ 中间地带(两者之间的中间件)

UseAuthorization / UseCors
已知目标 Endpoint,可读取其元数据
(授权策略、CORS 策略等)

🟣 阶段二:UseEndpoints(端点执行)

从 HttpContext 读取已选中的 Endpoint

执行 Endpoint 的 RequestDelegate

Controller Action / RazorPage / Lambda...

🔵 阶段一:UseRouting(路由匹配)

解析请求 URL 和 HTTP Method

遍历路由表,找到最匹配的 Endpoint

将 Endpoint 写入 HttpContext.Features

这种两阶段设计的核心价值是:让中间件在请求被执行之前,就能知道"这个请求要去哪里",从而做出更精准的决策。


三、UseRouting 详解

3.1 它做了什么

app.UseRouting();

调用这一行后,框架会在管道中注入 EndpointRoutingMiddleware,其核心行为:

  1. 解析 URL:提取路径、查询字符串、HTTP Method
  2. 遍历路由表:与所有已注册的 Endpoint 进行匹配(由 EndpointDataSource 提供)
  3. 写入结果:将匹配到的 Endpoint 对象存入 HttpContext

HttpContextEndpointDataSourceEndpointRoutingMiddlewareHTTP 请求HttpContextEndpointDataSourceEndpointRoutingMiddlewareHTTP 请求进入 UseRouting获取所有已注册 Endpoint返回路由表按优先级匹配路由SetEndpoint(matchedEndpoint)调用 next(),继续管道

3.2 匹配结果放在哪里

匹配结果通过 IEndpointFeature 接口存储在 HttpContext.Features 中,可以随时读取:

// 在任意后续中间件中读取当前匹配的 Endpoint
var endpoint = context.GetEndpoint();if (endpoint != null)
{Console.WriteLine($"匹配到端点:{endpoint.DisplayName}");// 读取元数据(如授权策略、路由名称等)var authAttr = endpoint.Metadata.GetMetadata<AuthorizeAttribute>();var routeName = endpoint.Metadata.GetMetadata<RouteNameMetadata>();
}

3.3 路由模板匹配规则

UseRouting 支持多种路由模板语法:

模板示例 说明
/products/{id} 基础参数捕获
/products/{id:int} 带类型约束的参数
/products/{id:int:min(1)} 多重约束
/files/{**path} 通配符(贪婪匹配剩余所有路径段)
/api/v{version:apiVersion} 结合 API 版本控制

路由约束内置类型包括:intlongboolguiddatetimealpharegex()minlength()range() 等。

3.4 路由优先级

当多个路由可以匹配同一请求时,框架按以下原则选择最佳匹配:

所有候选路由

字面量段优先于参数段

有约束的参数优先于无约束的参数

非通配符优先于通配符

HTTP Method 精确匹配优先

选出唯一最优路由
写入 HttpContext


四、UseEndpoints 详解

4.1 它做了什么

app.UseEndpoints(endpoints =>
{endpoints.MapControllers();endpoints.MapRazorPages();endpoints.MapGet("/health", () => "OK");
});

UseEndpoints 做两件事:

① 注册阶段(应用启动时):将 Lambda、Controller、RazorPage 等封装为 Endpoint 对象,添加到 EndpointDataSource,供 UseRouting 查询。

② 执行阶段(请求到来时):从 HttpContext 读取 UseRouting 已经选好的 Endpoint,执行其 RequestDelegate

4.2 Endpoint 的内部结构

每个 Endpoint 对象包含三个核心部分:

Endpoint 对象

RequestDelegate
实际执行逻辑
(Action / Lambda)

MetadataCollection
元数据集合
(授权策略 / CORS / 路由名称...)

DisplayName
调试用描述名称

RouteEndpointEndpoint 的子类,额外携带 RoutePatternOrder 信息 。

4.3 常见的 注册 方式

app.UseEndpoints(endpoints =>
{// MVC Controllerendpoints.MapControllers();// 带属性路由的 Controllerendpoints.MapControllerRoute(name: "default",pattern: "{controller=Home}/{action=Index}/{id?}");// Razor Pagesendpoints.MapRazorPages();// SignalR Hubendpoints.MapHub<ChatHub>("/chathub");// gRPC 服务endpoints.MapGrpcService<GreeterService>();// 最小 API(Minimal API)endpoints.MapGet("/api/ping", () => "pong");endpoints.MapPost("/api/echo", async (HttpRequest req) =>{var body = await new StreamReader(req.Body).ReadToEndAsync();return Results.Ok(body);});// 带元数据的端点endpoints.MapGet("/admin/data", AdminHandler).RequireAuthorization("AdminPolicy")   // 附加授权策略.RequireCors("AllowAll")               // 附加 CORS 策略.WithName("AdminData")                 // 设置路由名称.WithDisplayName("管理数据接口");
});

五、两者之间的"黄金地带"

这是整个端点路由设计中最精妙的地方。

中间地带

UseAuthentication
验证身份

UseAuthorization
检查权限策略

UseCors
检查 CORS 策略

UseRateLimiter
读取限流元数据

UseRouting
✅ Endpoint 已确定

⚡ 这里的中间件可以读取 Endpoint 元数据!

C

UseEndpoints
执行 Endpoint

为什么 UseAuthorization 必须在 UseRouting 之后?

因为授权中间件需要先知道"当前请求要访问哪个 Endpoint",才能去读取该 Endpoint 上附加的 [Authorize]RequireAuthorization() 元数据,进而判断当前用户是否有权限。

如果把 UseAuthorization 放在 UseRouting 之前,HttpContext 中还没有 Endpoint 信息,授权中间件就无从检查——这是一个常见的配置错误


六、.NET 6+ 的变化:WebApplication 与隐式调用

.NET 6 引入了 WebApplicationUseRoutingUseEndpoints 的使用方式发生了变化:

// .NET 6+ Minimal API 风格
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();var app = builder.Build();// ✅ 不再需要显式调用 UseRouting / UseEndpoints
// MapControllers 内部会自动触发
app.MapControllers();
app.MapGet("/health", () => Results.Ok("healthy"));app.Run();

当你调用 MapControllers()MapGet() 等方法时,框架会自动在合适的位置插入等价的 UseRoutingUseEndpoints 逻辑。

但在以下情况下,仍需显式调用:

// 当你需要在 UseRouting 和 UseEndpoints 之间插入自定义中间件时
app.UseRouting();// 自定义中间件(此时可以读取 Endpoint 元数据)
app.Use(async (context, next) =>
{var endpoint = context.GetEndpoint();var myMeta = endpoint?.Metadata.GetMetadata<MyCustomMetadata>();// ... 基于元数据做决策await next();
});app.UseAuthorization();app.UseEndpoints(endpoints =>
{endpoints.MapControllers();
});

七、自定义路由约束

当内置约束不满足需求时,可以实现 IRouteConstraint

// 自定义约束:只允许特定国家代码
public class CountryCodeConstraint : IRouteConstraint
{private static readonly HashSet<string> _validCodes =new(StringComparer.OrdinalIgnoreCase) { "CN", "US", "UK", "JP" };public bool Match(HttpContext? httpContext,IRouter? route,string routeKey,RouteValueDictionary values,RouteDirection routeDirection){if (values.TryGetValue(routeKey, out var value)){return _validCodes.Contains(value?.ToString() ?? "");}return false;}
}// 注册约束
builder.Services.AddRouting(options =>
{options.ConstraintMap.Add("countryCode", typeof(CountryCodeConstraint));
});// 使用约束
app.MapGet("/api/{country:countryCode}/products", (string country) =>Results.Ok($"Products for {country}"));

八、链路梳理:一次完整请求的生命周期

Controller/HandlerUseEndpointsUseAuthorizationUseRoutingKestrel客户端Controller/HandlerUseEndpointsUseAuthorizationUseRoutingKestrel客户端解析 URL匹配路由表选中 Endpoint读取 [Authorize] 元数据验证用户身份与权限读取 HttpContext 中的 Endpoint执行 RequestDelegateGET /api/products/42传入 HttpContextnext(),Endpoint 已写入 Contextnext(),授权通过调用 ProductsController.Get(42)返回 JSON 响应


九、常见错误与最佳实践

❌ 错误示例

// 错误一:UseAuthorization 放在 UseRouting 之前
app.UseAuthorization();  // ❌ 此时 Endpoint 未知,无法读取授权元数据
app.UseRouting();// 错误二:UseEndpoints 放在 UseRouting 之前
app.UseEndpoints(e => e.MapControllers()); // ❌ 路由还未匹配
app.UseRouting();

✅ 正确顺序

app.UseExceptionHandler("/error");   // 1. 最外层,捕获所有异常
app.UseHttpsRedirection();           // 2. HTTPS 重定向
app.UseStaticFiles();                // 3. 静态文件(短路,不进入路由)
app.UseCookiePolicy();               // 4. Cookie 策略app.UseRouting();                    // 5. ✅ 路由匹配app.UseAuthentication();             // 6. ✅ 身份验证(需在 UseRouting 之后)
app.UseAuthorization();              // 7. ✅ 授权(读取 Endpoint 元数据)
app.UseCors();                       // 8. ✅ CORS(读取 Endpoint 元数据)
app.UseRateLimiter();                // 9. ✅ 限流(读取 Endpoint 元数据)app.UseEndpoints(endpoints =>        // 10. ✅ 最后执行端点
{endpoints.MapControllers();endpoints.MapRazorPages();
});

最佳实践总结

实践 说明
遵守中间件顺序 UseRouting → 策略中间件 → UseEndpoints
善用元数据 RequireAuthorization()RequireCors() 等在端点粒度配置策略
避免过度使用全局过滤器 端点级策略比全局中间件更精确、性能更好
.NET 6+ 优先用 Minimal API MapGet 等方法语义更清晰,配合 WithMetadata() 灵活扩展
理解"黄金地带" 需要读 Endpoint 元数据的中间件,务必放在两者之间

十、总结

Endpoint 已选定
写入 HttpContext

授权 / CORS / 限流
通过检查

UseRouting
📍 我来决定
去哪个 Endpoint

中间层中间件
🔍 我来决定
要不要放行

UseEndpoints
⚡ 我来负责
真正执行

UseRouting侦察兵,负责找到目标;中间地带的中间件是守门人,负责把关;UseEndpoints执行者,负责干活。三者各司其职,共同构成 ASP.NET Core 高可扩展路由系统的基石。

理解这套机制,不仅能帮助你避免配置错误,更能让你在构建自定义中间件、API 网关、权限系统时,做出更优雅、更高效的设计决策。

http://www.jsqmd.com/news/863376/

相关文章:

  • 2026 横评6款论文降 AI 率工具:早标网最低1.1元优惠,AI 率 100%→0%真好用 - 全维度降AI
  • 国内紧凑式电磁流量计优质厂家推荐,源头生产厂家盘点 - 陈工日常
  • 3分钟搞定!Dell G15终极散热控制:开源神器tcc-g15完全指南
  • 芯片测试技术:DFT与SSI的核心差异与应用
  • 银川基坑护栏加工哪家专业?宁夏路弘本地工地护栏定制厂家推荐 - 宁夏壹山网络
  • Warcraft Helper终极优化指南:如何在现代Windows系统上完美运行经典魔兽争霸III
  • 四足机器人运动控制:NMPC与多任务学习融合框架
  • 广元 CPPM 注册采购经理授权中心及电话 - 中供国培
  • 3MF格式插件:解锁Blender在3D打印工作流中的终极潜力
  • 最全攻略:话费充值卡变现的注意事项和常见问题解析 - 团团收购物卡回收
  • 三分钟掌握QQ空间备份:永久保存青春记忆的终极指南
  • 魔兽争霸3终极优化指南:5个简单步骤让经典游戏在现代系统上完美运行
  • 一个月使用体验分享Taotoken平台稳定性与延迟观感
  • ARM T32指令集与SIMD技术深度解析
  • 【8】面试官:synchronized 锁原理知道吗?说下锁的升级过程
  • AI双轨制实战指南:MoE架构、异构模态与弹性推理的工程落地
  • AArch64虚拟化调试:HDFGWTR2_EL2寄存器详解与应用
  • git fsck 深度解析 Git 仓库的体检医生
  • 汽车软件维护性挑战与架构优化实践
  • 软考高项案例分析7:项目沟通管理
  • 多域名单证书如何配置 Nginx 实现共用同一个 SSL 证书
  • 5分钟搞定百度网盘限速:baidu-wangpan-parse全功能指南
  • 基于微信小程序的社区遗失物品登记与认领系统
  • 3分钟解锁:让魔兽争霸3在现代Windows系统上完美运行的完整指南
  • 2026年还在为去AI痕迹困扰?这7款降AI工具实测有效,助力提升论文通过率! - 降AI实验室
  • Mixtral 8x7B:稀疏专家模型(MoE)高效推理实战指南
  • 2026邯郸装修公司综合实力测评指南(业主实测版) - GEO排行榜
  • MoE大模型稀疏激活原理与生产部署实战
  • 终极M3U8下载指南:N_m3u8DL-CLI-SimpleG的完整使用教程
  • 2026年05月20日最热门的开源项目(Github)