请求管道与 Endpoint 注册
AgileLabs Framework 通过 RequestPiplineCollection、IRequestPiplineRegister 与 IEndpointConfig 统筹 ASP.NET Core 中间件。这个机制的价值不只是“自动扫描”,而是把宿主、功能模块和业务项目都放进一条可排序、可观察、可扩展的请求装配链。
核心源码入口
AgileLabs.WebApp/AgileLabContext.cs:ConfigureRequestPipeline(...)的总装配入口。AgileLabs.WebApp/AppRegisters/RequestPiplineCollection.cs:中间件注册容器。AgileLabs.WebApp/AppRegisters/RequestPipelineStage.cs:阶段枚举。AgileLabs.WebApp/IRequestPiplineRegister.cs:业务注册扩展点。AgileLabs.WebApp/IEndpointConfig.cs:终结点注册扩展点。
管道阶段全景
框架先执行一批固定基础中间件,再把自动发现的中间件按阶段和顺序插入,最后再进入 UseEndpoints()。
flowchart TD
A[HttpWorkContextInitMiddleware]
B[UseCookiePolicy]
C[UseForwardedHeaders]
D[修正 X-Forwarded-Proto]
E[BeginOfPipeline]
F[BeforeRouting]
G[UseRouting]
H[框架认证授权开关]
I[BeforeEndpointConfig]
J[UseEndpoints + IEndpointConfig]
K[AfterEndpointConfig]
A --> B --> C --> D --> E --> F --> G --> H --> I --> J --> K
RequestPiplineCollection 的职责
RequestPiplineCollection 是一个带去重能力的注册表,而不是简单列表:
public class RequestPiplineCollection : Dictionary<string, RequestPiplineItem>
{
public void Register(Action<IApplicationBuilder> action)
{
Register(Guid.NewGuid().ToString(), RequestPipelineStage.BeforeRouting, action);
}
public void Register(string name, RequestPipelineStage stage, Action<IApplicationBuilder> action, int stageOrder = 100)
{
var addResult = TryAdd(name, new RequestPiplineItem
{
Name = name,
Action = action,
Stage = stage,
StageOrder = stageOrder
});
if (!addResult)
{
throw new Exception($"已经存在名称为{name}的配置项");
}
}
}
name:唯一键。重复注册同名中间件会直接报错。stage:决定它在请求大阶段中的位置。stageOrder:决定同一阶段内的排序,值越小越早执行。
RequestPipelineStage 典型用途
| Stage | 典型职责 |
|---|---|
BeginOfPipeline |
全局异常、请求统计、活动追踪等最早期中间件 |
BeforeRouting |
静态资源、ClientApp、CORS、路由前诊断逻辑 |
BeforeEndpointConfig |
认证、授权、自定义终结点前置逻辑 |
AfterEndpointConfig |
健康检查、Metrics、Fallback 等终结点后的处理 |
自动发现与装配顺序
框架装配过程可以简化成下面这个时序:
sequenceDiagram
participant Host as AgileLabContext
participant Finder as ITypeFinder
participant Register as IRequestPiplineRegister
participant App as IApplicationBuilder
participant Endpoints as IEndpointConfig
Host->>Finder: 扫描 IRequestPiplineRegister
Finder-->>Host: 框架 + 自定义注册类型
Host->>Register: 逐个执行 Configure()
Register-->>Host: 写入 RequestPiplineCollection
Host->>App: 按 Stage + StageOrder 依次执行 Action
Host->>App: UseRouting()
Host->>App: UseAuthentication()/UseAuthorization() if enabled
Host->>App: UseEndpoints(...)
Host->>Endpoints: 逐个执行 ConfigureEndpoints()
这里有两个很重要的事实:
- 框架命名空间下的
IRequestPiplineRegister会优先于业务自定义注册执行。 IEndpointConfig不是随时插入的,它固定发生在UseEndpoints()这个阶段。
IRequestPiplineRegister 示例
public class AppConfigure : IRequestPiplineRegister
{
public RequestPiplineCollection Configure(RequestPiplineCollection pipelines, AppBuildContext context)
{
pipelines.Register("staticfiles", RequestPipelineStage.BeforeRouting, app =>
{
app.UseStaticFiles();
app.UseClientApp();
}, stageOrder: 10);
pipelines.Register("auth", RequestPipelineStage.BeforeEndpointConfig, app =>
{
app.UseAuthentication();
app.UseAuthorization();
}, stageOrder: 20);
return pipelines;
}
}
实践上建议:
- 给每个注册项取稳定、可检索的名字。
- 对会影响最终顺序的中间件显式写
stageOrder。 - 把“为什么一定要在这个阶段注册”写进代码注释或文档,不要只靠口口相传。
Endpoint 注册
实现 IEndpointConfig 可在 UseEndpoints 阶段追加映射:
public class AppEndpoints : IEndpointConfig
{
public void ConfigureEndpoints(IEndpointRouteBuilder endpoints, AppBuildContext context)
{
endpoints.MapControllers();
endpoints.MapSwagger();
endpoints.MapHangfireDashboard();
}
}
终结点本身不会帮你补齐前面的中间件顺序,所以如果某个功能依赖认证、CORS、静态资源或 WorkContext 初始化,必须先检查它们是不是已经在正确阶段挂上了。
顺序冲突时怎么看
先看日志。AgileLabContext.ConfigureRequestPipeline() 会输出类似记录:
[AutoRequestPipeline-BeforeRouting-01]: BeforeRouting-staticfiles
[ASPNETCORE-STAGE]=>UseRouting
[ASPNETCORE-STAGE]=>UseEndpoints
如果某个中间件没有生效,排查顺序通常是:
- 该类型是否真的实现了
IRequestPiplineRegister或IEndpointConfig。 - 类型过滤器有没有把它排除。
- 是否和现有注册项重名。
- 是否注册到了错误阶段,导致顺序天然不成立。
与其他主题的关系
- WebAPI 过滤器和认证授权,最终都要落回这条请求管道。
- WorkContext 的 HTTP 自动初始化,是这条管道最前面的基础动作。
- 静态资源托管、诊断页、前端托管等能力,也都应该从“阶段和顺序”来理解,而不是只看单个功能页。