集成上下文(IntegrationContext)在调用链中传播租户、地区、环境和关联 ID,让 Provider 在调用第三方 API 时能附带正确的上下文信息。
IntegrationContext
不可变值对象,通过 With() 方法创建副本:
public sealed class IntegrationContext{ public string? TenantId { get; } public string? Region { get; } public string? Environment { get; } public string? CorrelationId { get; }
// ① With() 返回修改后的副本,原实例不变 public IntegrationContext With( string? tenantId = null, string? region = null, string? environment = null, string? correlationId = null);}IIntegrationContextAccessor
基于 AsyncLocal<T> 的作用域传播器,Singleton 生命周期:
public interface IIntegrationContextAccessor{ IntegrationContext? Current { get; }
// ① Push 返回 IDisposable,using 块结束时自动恢复上一个上下文 IDisposable Push(IntegrationContext context);}使用方式
public class TenantMiddleware(IIntegrationContextAccessor contextAccessor) : IMiddleware{ public async Task InvokeAsync(HttpContext context, RequestDelegate next) { // ① 从 HTTP 请求中提取租户和关联 ID var tenantId = context.User.FindFirst("tenant_id")?.Value; var correlationId = context.TraceIdentifier;
var integrationContext = new IntegrationContext() .With(tenantId: tenantId, correlationId: correlationId);
// ② Push 到 AsyncLocal 作用域,下游所有 Provider 都能读到 using (contextAccessor.Push(integrationContext)) { await next(context); } // ③ using 块结束,上下文自动恢复 }}// Provider 实现中读取上下文public class PaymentService( IPaymentProvider payment, IIntegrationContextAccessor contextAccessor){ public async Task PayAsync(PaymentOrderRequest request) { var ctx = contextAccessor.Current; if (ctx?.TenantId is not null) { // ① 带上租户上下文调用第三方 API request.Extra["tenant_id"] = ctx.TenantId; }
await payment.CreateOrderAsync(request); }}生命周期
| 组件 | 生命周期 | 说明 |
|---|---|---|
IIntegrationContextAccessor | Singleton | AsyncLocal<T> 天然按异步调用链隔离 |
IntegrationContext | 不可变 | 每次 With() 创建新实例 |