Skip to content
Bitzsoft.Integrationsbitzsoft.integrations

Reference

ADR-0005:使用跨框架 Provider Catalog 与 Resolver

引入 IntegrationProviderDescriptor、Catalog 和 Resolver 解决多 Provider 路由的设计决策。

Last updated
  • 状态:已接受
  • 日期:2026-07-24
  • 取代:ADR-0003

背景

.All 聚合包允许同时配置多个厂商,但旧注册使用 TryAddSingleton<TCapability, TProvider>

  • 直接注入共享接口时只有首个 Provider 可见;
  • IEnumerable<T> 也不能恢复被 TryAdd 丢弃的实现;
  • 运行时按租户、地区或业务线选择 Provider 没有统一入口;
  • Singleton Provider 会捕获 typed/factory HttpClient,形成错误生命周期;
  • 包存在、接口实现和真实可用能力之间没有可查询的事实源。

.NET 8 keyed services 能解决部分问题,但本仓库的长期兼容基线包含 net5.0,公共契约不能依赖 keyed DI。

决策

引入目标化 net5.0;net8.0;net10.0Bitzsoft.Integrations.Core

  • IntegrationProviderDescriptor 是 Provider ID、领域、厂商、API、鉴权、地区、环境、稳定性、限制和真实能力的事实源;
  • IIntegrationProviderCatalog 枚举当前容器中所有已配置 Provider;
  • IIntegrationProviderResolver<TCapability> 按大小写不敏感的稳定 Provider ID 解析能力;
  • Provider 跨领域唯一键为 {Domain}:{ProviderId}
  • resolver 使用 scoped 字典 Adapter,不依赖 .NET 8 keyed services;
  • HTTP Provider 与其客户端默认使用 Transient;只有明确管理有状态长连接并自行保证并发安全的 Adapter 才保留 Singleton;
  • 单 Provider 应用仍可直接注入能力接口,作为兼容别名;多 Provider 应用必须使用 resolver;
  • .All 包必须有测试证明每个配置 Provider 可枚举、可按 ID 解析,且只暴露真实能力。

Provider ID 是持久配置值,发布后不得因显示名称或类名变化而修改。

备选方案

  1. 继续由消费方使用 IEnumerable<T> 自行查找:无法解决 TryAdd 已丢弃实现的问题,也没有统一元数据和错误语义。
  2. 只使用 .NET 8 keyed services:会破坏 net5.0 兼容。
  3. 每个领域定义独立 Factory:可以工作,但重复注册、查找、异常和测试逻辑。
  4. 移除直接接口注入:语义最严格,但会立即破坏现有单 Provider 应用。

后果

正面:

  • 多厂商配置不再依赖注册顺序;
  • 能力声明可以与运行时解析及支持矩阵校验;
  • net5.0、net8.0、net10.0 使用同一公共 API;
  • internal 构造函数可通过包内显式工厂安全注册;
  • 生命周期可被 DI 集成测试验证。

代价:

  • 多 Provider 消费方需要注入 resolver;
  • 兼容期内直接能力接口仍代表单 Provider 用法,不能表达路由意图;
  • 现有宽接口尚需逐步拆为更细能力,否则 Descriptor 只能记录限制,无法彻底阻止调用厂商不支持的方法。

迁移

旧代码(只配置一个 Provider)可以保持:

public sealed class SingleProviderService(IPaymentProvider payment) { }

多 Provider 代码改为:

public sealed class PaymentRouter(
IIntegrationProviderResolver<IPaymentProvider> providers)
{
public IPaymentProvider Resolve(string providerId)
=> providers.GetRequired(providerId);
}

撤销条件

只有在 net5.0 兼容策略被新的 ADR 正式结束,且 keyed services 能同时覆盖 Catalog、能力元数据和兼容迁移时,才重新评估底层实现;公共 resolver 契约应尽量保持。

相关

100%

滚轮或按钮缩放 · 放大后拖动画面 · 双击切换 100% / 200%