Skip to content
Bitzsoft.Integrationsbitzsoft.integrations

Reference

Integration Core

Core 包完整 API 参考——Provider 描述、目录、解析器、上下文、凭据、异常与 DI 注册。

Last updated

Core 是连接器库的”事实源”层。它定义 Provider 能力描述、跨 TFM 的目录与解析器、调用上下文、凭据模型和统一异常基类。所有域抽象层都依赖 Core,但 Core 不依赖任何域抽象,也不依赖 .NET 8 keyed services,在 net5.0 上完全工作。本页是 Core 公共 API 的完整参考。

包信息

NuGet IDBitzsoft.Integrations.Core
目标框架net5.0;net8.0;net10.0
命名空间Bitzsoft.Integrations.Core
DI 扩展命名空间Microsoft.Extensions.DependencyInjection

类型总览

IntegrationProviderDescriptor
ID · 领域 · 能力 · 稳定性

IIntegrationProviderCatalog
枚举全部 Provider

IIntegrationProviderResolver
按 ID 解析能力

IContextualIntegrationProviderResolver
按地域/环境解析

IntegrationContext
租户 · 地域 · 环境

IntegrationCredential
可清零凭据快照

IntegrationException
结构化异常基类

IntegrationProviderDescriptor

每个 Provider 的可执行能力描述,是 DI 注册与支持矩阵的事实源。该类型 sealed 且不可变,构造完成后所有属性只读。

public sealed class IntegrationProviderDescriptor
{
public IntegrationProviderDescriptor(
string providerId,
string displayName,
string domain,
IEnumerable<Type> capabilityTypes,
IntegrationProviderStability stability,
string? vendor = null,
string? apiVersion = null,
string? authenticationType = null,
IEnumerable<string>? regions = null,
IEnumerable<string>? environments = null,
IEnumerable<string>? limitations = null,
DateTimeOffset? lastContractValidatedAt = null);
}

属性说明:

属性类型说明
ProviderIdstring稳定、大小写不敏感的标识,发布后不可修改
ProviderKeystring跨领域唯一键,格式 {Domain}:{ProviderId}
DisplayNamestring面向用户的显示名称
Domainstring所属连接器领域,如 PaymentFileStorage
Vendorstring?厂商名称
ApiVersionstring?已适配的厂商 API 版本
AuthenticationTypestring?鉴权类型,如 RSA2OAuth2
StabilityIntegrationProviderStability支持级别
CapabilityTypesIReadOnlyCollection<Type>已实现并会注册到 resolver 的能力类型
RegionsIReadOnlyCollection<string>适用地区,空集合表示未限定
EnvironmentsIReadOnlyCollection<string>适用环境,空集合表示未限定
LimitationsIReadOnlyCollection<string>已知限制
LastContractValidatedAtDateTimeOffset?最近一次通过厂商契约验证的时间

构造函数会对 providerIddisplayNamedomaincapabilityTypes 做非空校验,ProviderKeyDomainProviderId 自动拼接。RegionsEnvironmentsLimitations 会被规范化:去空白、去重(大小写不敏感)、排序。

Supports 方法判断描述是否声明了指定能力:

// ① 泛型形式,最常用
if (!descriptor.Supports<IPaymentProvider>())
throw new ArgumentException("Descriptor does not declare this capability.");
// ② Type 形式,适合反射场景
bool ok = descriptor.Supports(typeof(IPaymentProvider));

AddIntegrationProviderCapability 注册时会用 Supports<TCapability>() 校验描述确实声明了该能力,否则抛出 ArgumentException

Stability 枚举

public enum IntegrationProviderStability
{
Experimental = 0, // 仅设计验证或项目级适配,不作生产能力声明
Preview = 1, // 有真实实现与测试,公共契约仍可能调整
Stable = 2, // 已通过契约测试,可作为受支持能力使用
Deprecated = 3 // 仍兼容但不建议新项目使用
}

Stability 是声明值,由各 Provider 在自己的 Descriptor 中给出,宿主可据此决定是否启用告警或路由策略。

IIntegrationProviderCatalog

枚举当前容器中所有已配置 Provider。

public interface IIntegrationProviderCatalog
{
IReadOnlyCollection<IntegrationProviderDescriptor> Providers { get; }
bool TryGet(string providerKey, out IntegrationProviderDescriptor descriptor);
bool TryGet(string domain, string providerId, out IntegrationProviderDescriptor descriptor);
IntegrationProviderDescriptor GetRequired(string providerKey);
}

GetRequired 在找不到时抛出 IntegrationProviderResolutionExceptionProviders 集合按 ProviderKey 去重,注册阶段会拒绝用不同实例重复注册同一 key。

IIntegrationProviderResolver<T>

按大小写不敏感的稳定 Provider ID 解析能力,是跨 TFM 多 Provider 路由的 canonical API。

public interface IIntegrationProviderResolver<TCapability> where TCapability : class
{
IReadOnlyCollection<TCapability> Providers { get; }
bool TryResolve(string providerId, out TCapability capability);
TCapability GetRequired(string providerId);
}

GetRequired 找不到时抛出 IntegrationProviderResolutionException(继承自 InvalidOperationException),携带 ProviderIdCapabilityType。单 Provider 应用可直接注入能力接口,多 Provider 应用必须使用 resolver。

IContextualIntegrationProviderResolver<T>

按显式或环境中的地域、环境条件解析 Provider,用于需要按租户驻留地路由的场景。

public interface IContextualIntegrationProviderResolver<TCapability> where TCapability : class
{
IReadOnlyCollection<IntegrationProviderDescriptor> Providers { get; }
bool TryResolve(IntegrationProviderSelection selection, out TCapability? provider);
TCapability GetRequired(IntegrationProviderSelection selection);
}

TryResolve 无候选返回 false;多个自动候选时抛出异常,避免静默猜测。GetRequired 在无候选或候选不唯一时抛出明确异常。

IntegrationContext

一次连接器调用的租户、地域和运行环境上下文。sealed 且不可变。

public sealed class IntegrationContext
{
public IntegrationContext(
string tenantId,
string? region = null,
string? environment = null,
string? correlationId = null);
public string TenantId { get; }
public string? Region { get; }
public string Environment { get; } // 默认 Production
public string? CorrelationId { get; }
public IntegrationContext With(
string? region = null,
string? environment = null,
string? correlationId = null);
}

With 以不可变方式创建仅替换指定字段的新上下文,原实例不变。Environment 未指定时默认为 IntegrationEnvironments.Production

IIntegrationContextAccessor

访问当前异步调用链中的连接器上下文。基于 AsyncLocal<T> 实现,跨 await 自动流转。

public interface IIntegrationContextAccessor
{
IntegrationContext? Current { get; }
IDisposable Push(IntegrationContext context);
}

Push 在当前异步调用链中压入上下文作用域,必须按后进先出顺序释放返回的 IDisposable

// ③ 建立短生命周期作用域,using 保证释放
using (accessor.Push(new IntegrationContext("tenant-001", region: "CN")))
{
await payment.CreateOrderAsync(request);
}

IntegrationCredential

可释放的 Provider 凭据快照。密钥仅保存在可清零的 char[] 缓冲区中,不通过属性、ToString 或调试显示暴露,Dispose 时清零。

public sealed class IntegrationCredential : IDisposable
{
public IntegrationCredential(
IEnumerable<KeyValuePair<string, string>> secrets,
string name = IntegrationCredentialNames.Default,
string? authenticationType = null,
DateTimeOffset? expiresAt = null);
public string Name { get; }
public string? AuthenticationType { get; }
public DateTimeOffset? ExpiresAt { get; }
public IReadOnlyCollection<string> SecretNames { get; } // 仅字段名,不含值
public bool IsDisposed { get; }
public bool IsExpiredAt(DateTimeOffset instant);
public bool TryGetSecret(string secretName, out string? value);
public bool ContainsSecret(string secretName);
public string GetRequiredSecret(string secretName);
public TResult UseSecret<TResult>(string secretName, Func<ReadOnlyMemory<char>, TResult> callback);
}

GetRequiredSecretTryGetSecret 会不可避免地创建托管字符串,调用方应缩短其生命周期。UseSecret 在缓冲区有效期间执行回调,避免由本类型主动创建字符串,是签名计算的推荐方式:

// ① UseSecret 在 char[] 有效期内计算 HMAC,不产生中间 string
byte[] signature = credential.UseSecret("RequestSigningSecret", secret =>
{
var key = Encoding.UTF8.GetBytes(secret.ToArray());
using var hmac = new HMACSHA256(key);
return hmac.ComputeHash(canonical);
});

Resolver 返回的实例归调用方所有,使用后应 Dispose(或用 using)。

IIntegrationCredentialStore / IIntegrationCredentialResolver

IIntegrationCredentialStore 是凭据存储抽象,IIntegrationCredentialResolver 是按 IntegrationCredentialKey 解析凭据的接口。生产宿主应优先接入 Vault、KMS 或云密钥服务,并自行注册 IIntegrationCredentialResolver

InMemoryIntegrationCredentialStore

进程内凭据存储,主要用于开发与测试。AddInMemoryIntegrationCredentials() 同时把它注册为 IIntegrationCredentialStoreIIntegrationCredentialResolver 的实现。

var store = new InMemoryIntegrationCredentialStore();
store.Store(new IntegrationCredentialKey("tenant-001", "Payment:Alipay"),
new IntegrationCredential(new[]
{
new KeyValuePair<string, string>("AppId", "2021..."),
new KeyValuePair<string, string>("PrivateKey", "..."),
}, authenticationType: "RSA2"));

IntegrationException

所有连接器领域可选用的统一结构化异常基类。宿主无需依赖每个供应商的具体异常即可实施统一错误映射、告警和重试决策。

public class IntegrationException : Exception
{
public IntegrationException(
string domain,
string message,
string? provider = null,
string? errorCode = null,
string? providerMessage = null,
IntegrationFailureKind failureKind = IntegrationFailureKind.Provider,
int? httpStatusCode = null,
string? requestId = null,
bool isTransient = false,
TimeSpan? retryAfter = null,
Exception? innerException = null);
}

结构化字段:

字段说明
Domain连接器领域,如 PaymentRest
Provider供应商稳定标识或名称
ErrorCode供应商或协议错误码
ProviderMessage供应商返回的原始错误消息,不得默认包含凭据
FailureKind稳定失败分类
HttpStatusCode可用时记录的 HTTP 状态码(100–599)
RequestId供应商请求 ID、追踪 ID 或关联 ID
IsTransient是否可在满足幂等性约束后重试
RetryAfter供应商建议的最短重试等待时间

构造函数校验 httpStatusCode 必须在 100–599 之间,retryAfter 不能为负。

IntegrationFailureKind

13 个稳定失败分类,供宿主统一映射状态码、告警与重试策略:

名称含义
0Unknown无法进一步分类
1Configuration配置缺失或配置值无效
2Authentication身份认证失败或凭据已失效
3Authorization身份有效但没有执行操作的权限
4Validation请求参数或业务数据校验失败
5NotFound目标资源不存在
6Conflict资源状态冲突或重复提交
7RateLimited供应商限流
8Network网络、DNS、TLS 或连接层失败
9Timeout调用超时
10Provider供应商返回业务或服务端错误
11Unsupported当前 Provider 或版本不支持所请求能力
12Cancelled调用被取消

IntegrationProviderResolutionException

Provider 注册或解析失败时抛出,继承自 InvalidOperationException

public sealed class IntegrationProviderResolutionException : InvalidOperationException
{
public IntegrationProviderResolutionException(
string providerId, Type capabilityType, string message);
public string ProviderId { get; }
public Type CapabilityType { get; }
}

IIntegrationProviderResolver<T>.GetRequiredIIntegrationProviderCatalog.GetRequired 在找不到 Provider 时抛出此异常,携带失败的 Provider ID 和能力类型,便于定位。

DI 注册

Core 的 DI 扩展位于 Microsoft.Extensions.DependencyInjection 命名空间。

AddBitzsoftIntegrationCore

注册跨框架 Provider 目录、resolver、contextual resolver、catalog 和 context accessor。所有其他 Core 注册方法内部都会调用它,因此幂等且可安全重复调用。

// ① 注册基础设施:Resolver<>、ContextualResolver<>、Catalog、ContextAccessor
services.AddBitzsoftIntegrationCore();

注册的服务生命周期:

服务实现生命周期
IIntegrationProviderResolver<>IntegrationProviderResolver<>Scoped
IContextualIntegrationProviderResolver<>ContextualIntegrationProviderResolver<>Scoped
IIntegrationProviderCatalogIntegrationProviderCatalogScoped
IIntegrationContextAccessorIntegrationContextAccessorSingleton

AddInMemoryIntegrationCredentials

注册进程内凭据存储。内部先调用 AddBitzsoftIntegrationCore,再把 InMemoryIntegrationCredentialStore 同时绑定为 IIntegrationCredentialStoreIIntegrationCredentialResolver

services.AddInMemoryIntegrationCredentials();

AddIntegrationProviderDescriptor

将 Provider 描述加入目录,即使实验性 Provider 暂未暴露任何能力也可被发现。按 ProviderKey 去重:同一 key 用相同实例重复注册是幂等的,用不同实例则抛出 ArgumentException

services.AddIntegrationProviderDescriptor(AlipayProviderDescriptor.Instance);

AddIntegrationProviderCapability

注册 Provider 的一个真实能力。这是连接器库最核心的注册方法:

// ② 类型形式
services.AddIntegrationProviderCapability<IPaymentProvider, AlipayPaymentProvider>(
AlipayProviderDescriptor.Instance,
implementationLifetime: ServiceLifetime.Transient,
registerLegacyAlias: true);
// ③ 工厂形式(Provider 构造函数含 internal Adapter 时必须用)
services.AddIntegrationProviderCapability<IPaymentProvider, AlipayPaymentProvider>(
AlipayProviderDescriptor.Instance,
serviceProvider => new AlipayPaymentProvider(
serviceProvider.GetRequiredService<AlipayHttpClient>(),
serviceProvider.GetRequiredService<IAlipayConfigProvider>(),
serviceProvider.GetRequiredService<ILogger<AlipayPaymentProvider>>()));

注册内部完成四件事:

  1. Supports<TCapability>() 校验描述声明了该能力;
  2. 提交 Descriptor 到目录(按 ProviderKey 去重);
  3. TryAdd 实现类型 + 添加 IntegrationProviderRegistration<T> 单例;
  4. net8+ 额外注册 keyed service(以 ProviderId 为 key),net5 跳过。

registerLegacyAlias = true(默认)会用 TryAdd 注册直接能力接口别名,兼容单 Provider 应用直接注入。多 Provider 应用不应依赖此别名,必须用 resolver。

消费模式

单 Provider 直接注入

public sealed class CheckoutService(IPaymentProvider payment)
{
public Task<PaymentResult<PaymentOrderResult>> PayAsync(PaymentOrderRequest req)
=> payment.CreateOrderAsync(req);
}

多 Provider 路由

public sealed class PaymentRouter(IIntegrationProviderResolver<IPaymentProvider> providers)
{
public IPaymentProvider Resolve(string providerId)
=> providers.GetRequired(providerId); // ④ 按稳定 ID 解析
}

相关

100%

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