agilelabs-fx-docs main fundamentals/agilelabs-application/request-pipeline.md

请求管道与 Endpoint 注册

AgileLabs Framework 通过 RequestPiplineCollectionIRequestPiplineRegisterIEndpointConfig 统筹 ASP.NET Core 中间件。这个机制的价值不只是“自动扫描”,而是把宿主、功能模块和业务项目都放进一条可排序、可观察、可扩展的请求装配链。

核心源码入口

  • AgileLabs.WebApp/AgileLabContext.csConfigureRequestPipeline(...) 的总装配入口。
  • 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()

这里有两个很重要的事实:

  1. 框架命名空间下的 IRequestPiplineRegister 会优先于业务自定义注册执行。
  2. 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

如果某个中间件没有生效,排查顺序通常是:

  1. 该类型是否真的实现了 IRequestPiplineRegisterIEndpointConfig
  2. 类型过滤器有没有把它排除。
  3. 是否和现有注册项重名。
  4. 是否注册到了错误阶段,导致顺序天然不成立。

与其他主题的关系

  • WebAPI 过滤器和认证授权,最终都要落回这条请求管道。
  • WorkContext 的 HTTP 自动初始化,是这条管道最前面的基础动作。
  • 静态资源托管、诊断页、前端托管等能力,也都应该从“阶段和顺序”来理解,而不是只看单个功能页。

相关页面