IApplicationBuilder 和 IEndpointRouteBuilder 均非线程安全,仅限应用启动时顺序配置;运行时动态路由应使用 DynamicRouteValueTransformer 或自定义 EndpointDataSource,而非并发调用 Map 方法。

ASP.NET Core 中 IApplicationBuilder 不是线程安全的,别在中间件里并发修改它
IApplicationBuilder 是构建请求处理管道的“装配线”,只在应用启动时(Startup.Configure 或 Program.cs 的 WebApplication 配置阶段)被顺序调用。它的 Use、UseMiddleware、Map 等方法不是为运行时并发调用设计的。
- 如果在某个中间件内部(比如异步任务中)偷偷调用
app.Use(...),会触发InvalidOperationException:“Builder is already in use” 或 “The builder has already been built” -
IApplicationBuilder内部持有对RequestDelegate链的引用,且其Build()方法仅执行一次;重复或并发调用会破坏管道一致性 - 常见误用场景:在健康检查中间件里动态注册新路由、在灰度中间件里根据 Header 注册临时终结点——这些都该移出
IApplicationBuilder生命周期
IEndpointRouteBuilder 的线程安全性取决于具体实现,但 MapControllers() 等扩展方法不是运行时 API
IEndpointRouteBuilder(如 WebApplication 实现的 EndpointRouteBuilder)本身是线程不安全的,但它通常只在应用初始化阶段被使用。关键在于:所有 MapXxx() 方法(MapControllerRoute、MapRazorPages、MapHub)都只是往内部路由表注册终结点描述符(EndpointDataSource),不涉及实时请求分发。
- 这些注册操作必须在
app.MapXXX()或endpoints.MapXXX()调用期间完成,不能在HttpContext.RequestServices解析出的任意服务中调用 - 若需运行时动态添加路由(例如插件系统),应通过自定义
EndpointDataSource+IEndpointRouteBuilder的底层机制实现,而非直接调用Map方法 -
MapControllers()本质是批量扫描程序集并生成ControllerActionEndpointConventionBuilder,它不检查并发,但也不允许在Build()后再调用
真正支持运行时动态路由的是 DynamicRouteValueTransformer 和 EndpointDataSource
如果你需要根据请求上下文(如租户 ID、Header、查询参数)改变路由行为,IApplicationBuilder 和 IEndpointRouteBuilder 都不是目标接口。正确路径是:
V5Shop网店系统是上海威博旗下产品之一,一款B to C网上开店软件,适合中小型企业及个人快速构建个性化网上商店。 V5SHOP采用最新的ASP.NET分层技术和AJAX技术,结合微软NET+MSSQL 2005平台运行,并且在开发过程中融入了大量电子商务管理、网络营销和用户体验理念让系统的安全性、稳定性、易用性和实用性都得到了空前的突破,真正达到了只要会打字就能够建设专业水准的电子商务平台。
- 用
DynamicRouteValueTransformer在匹配后动态改写RouteValueDictionary,它天然支持异步和并发请求 - 实现自定义
EndpointDataSource并注入IServiceCollection,配合后台定时刷新或事件驱动更新终结点集合(注意:更新时需保证ChangeToken通知消费者) - 避免在
Map链中嵌套app.Run(async ctx => { ... })并在里面调用endpoints.MapGet—— 这会导致InvalidOperationException: Cannot create child container from a resolved service
public class TenantRouteTransformer : DynamicRouteValueTransformer
{
public override async ValueTask TransformAsync(HttpContext httpContext, RouteValueDictionary values)
{
var tenant = httpContext.Request.Headers["X-Tenant"].FirstOrDefault();
if (!string.IsNullOrEmpty(tenant))
{
values["tenant"] = tenant;
}
return values;
}
}
并发模型的本质:ASP.NET Core 的请求处理是 per-request 的,但配置阶段是单次、顺序、不可重入的
整个框架把“配置”和“执行”严格分离:IApplicationBuilder 和 IEndpointRouteBuilder 属于配置期对象,它们的生命周期止于 app.Build();之后所有并发请求都走同一个已构建好的 RequestDelegate 链,由 EndpointRoutingMiddleware 和 EndpointMiddleware 协同完成路由匹配与执行。
- 不要试图在
HttpContext中拿到IApplicationBuilder实例 —— 它根本不会被注入到 DI 容器 -
IEndpointRouteBuilder也不是 Scoped 或 Transient 服务,它只作为WebApplication的内部属性存在,无法从HttpContext.RequestServices获取 - 最易忽略的一点:即使你用
WebHostBuilder手动构建多个IWebHost,每个实例的IApplicationBuilder仍只在其自身启动阶段有效,跨实例共享毫无意义









