Web 构建块为 BitzOrcas 配置 ASP.NET Core API 管道。它位于 API 宿主的组合根(BitzOrcas.Api.Composition)中,遵循 4 阶段注册模式。
4 阶段 DI 注册
// 阶段 1: 核心运行时(无数据库依赖)builder.Services.AddBitzOrcasCoreRuntime(configuration);
// 阶段 2: 持久化适配器(需要 ConnectionStrings + RabbitMq)builder.Services.AddBitzOrcasPersistenceAdapters(configuration);
// 阶段 3: 认证(JWT / HMAC / API Key)builder.Services.AddBitzOrcasAuthentication(configuration, environment);
// 阶段 4: API 管道(Mediator + JSON + OpenAPI + 限流器)builder.Services.AddBitzOrcasApiPipeline(configuration);中间件管道顺序
ExceptionHandler → CorrelationId → Authentication → DelegationToken→ TenantResolution → RequestAudit → Authorization → RateLimiter → Endpoints| 中间件 | 用途 |
|---|---|
ExceptionHandler | 全局 RFC 9457 ProblemDetails 处理器(最外层) |
CorrelationIdMiddleware | 生成/传播 X-Correlation-Id 头 |
Authentication | ASP.NET Core 内置(JWT / HMAC / API Key) |
DelegationTokenMiddleware | 验证委托(模拟)令牌 |
TenantResolutionMiddleware | 从请求解析 ITenantContext |
RequestAuditMiddleware | 入队审计条目供后台处理 |
Authorization | ASP.NET Core 基于策略的授权 |
RateLimiter | 租户 + 调用方分区的限流 |
Mediator 集成
BitzOrcas 使用 Mediator 配合源生成器——运行时无反射:
services.AddMediator(options =>{ options.Assemblies = [typeof(PingQuery).Assembly]; options.ServiceLifetime = ServiceLifetime.Scoped; options.PipelineBehaviors = [ typeof(LoggingPipelineBehavior<,>), typeof(AuthorizationPipelineBehavior<,>), typeof(ValidationPipelineBehavior<,>), typeof(IdempotencyPipelineBehavior<,>), typeof(TransactionPipelineBehavior<,>), typeof(ActivityAuditPipelineBehavior<,>), ];});Mapster 对象映射
通过 Mapster 进行对象映射(基于反射;按 ADR 0006 规划迁移至 Mapperly 以实现 AOT 兼容):
// 从 Application 程序集扫描所有 TypeAdapter 配置TypeAdapterConfig.GlobalSettings.Scan(typeof(MappingConfig).Assembly);System.Text.Json(AOT 安全)
所有 API 序列化使用源生成 JSON 上下文——兼容 Native AOT 裁剪:
services.ConfigureHttpJsonOptions(options =>{ options.SerializerOptions.TypeInfoResolverChain.Insert(0, ApiJsonSerializerContext.Default);});OpenAPI + Scalar UI
BitzOrcas 使用 .NET 内置 OpenAPI 支持,配合 Scalar 作为 API 文档 UI:
services.AddOpenApi(); // .NET 内置// Scalar UI 在 /scalar 提供限流
三种分区限流策略,具有每租户 + 每调用方键:
| 策略 | 算法 | 用途 |
|---|---|---|
userPolicy | 令牌桶 | 通用 REST API 端点 |
sensitivePolicy | 滑动窗口 | 登录、OTP、密码重置 |
fixedPolicy | 固定窗口 | 内部/低频服务 |
分区键格式:{tenant_id}:{user_id|client_id} — 防止应用调用方(无 user_id)共享同一匿名桶。
ProblemDetails 错误处理
所有异常由 GlobalExceptionHandler 转换为 RFC 9457 ProblemDetails:
{ "type": "https://docs.bitzsoft.com/problems/not-found", "title": "Not Found", "status": 404, "detail": "Note with ID 'abc' not found.", "instance": "/api/notes/abc", "traceId": "00-abc123-...", "correlationId": "corr-456", "requestId": "req-789", "errorCode": "Note.NotFound"}Result<T> 到 HTTP 的转换
ResultExtensions 提供扩展方法,用于在 Minimal API 端点中将 Result<T> 转换为 HTTP 响应:
app.MapPost("/api/notes", async ( CreateNoteCommand cmd, IMediator mediator) => await mediator.Send(cmd) switch { { IsSuccess: true } result => Results.Created( $"/api/notes/{result.Value.Id}", result.Value), var result => result.ToProblemDetails() });