Skip to content
Bitzsoft.Integrationsbitzsoft.integrations

Concept

DI 注册

DI 扩展方法命名、Provider 生命周期选择、单 Provider 兼容与多 Provider 路由、聚合包配置驱动注册。

Last updated

依赖注入注册是消费者使用连接器的唯一入口。本节约定扩展方法如何命名、Provider 注册成什么生命周期、单 Provider 与多 Provider 场景的区别,以及聚合 .All 包如何根据配置节存在性驱动注册。

扩展方法命名:两种风格

所有 DI 扩展方法注册在 Microsoft.Extensions.DependencyInjection 命名空间下,消费者 using 后即可链式调用。

风格公式示例适用域
推荐AddBitzsoft{Vendor}{Domain}()AddBitzsoftStripePayment()除 Sms 外全部
遗留Add{Vendor}Sms()AddAliyunSms()Sms
聚合AddBitzsoft{Domain}All()AddBitzsoftPaymentAll()所有 .All

推荐风格加 Bitzsoft 前缀,避免与其他集成库的同名扩展方法冲突。遗留 Sms 域因历史原因不加前缀,暂不改造。

Provider 生命周期

核心原则:HTTP Provider 用 Transient

AddIntegrationProviderCapability<TCapability, TImplementation>() 是注册 Provider 的标准 API,默认 ServiceLifetime.Transient。这是核心约定——HTTP Provider 不应是 Singleton,因为 typed HttpClient 不应被长生命周期对象捕获。

// Core 包提供的标准注册 API
public static IServiceCollection AddIntegrationProviderCapability<TCapability, TImplementation>(
this IServiceCollection services,
IntegrationProviderDescriptor descriptor,
ServiceLifetime implementationLifetime = ServiceLifetime.Transient, // ① 默认 Transient
bool registerLegacyAlias = true) // ② 单 Provider 兼容
where TCapability : class
where TImplementation : class, TCapability

各域生命周期分布

生命周期注册方式原因
PaymentTransientAddIntegrationProviderCapability默认,标准模式
TeamWorkTransientAddIntegrationProviderCapability避免 Singleton 捕获 typed HttpClient
OutboundCallTransientAddIntegrationProviderCapability默认
FinanceTransientAddIntegrationProviderCapability默认
FileStorageSingletonAddIntegrationProviderCapability(..., Singleton)底层 SDK 客户端有状态且构造昂贵
EnterpriseMail.NetEaseSingletonTryAddSingleton<NetEaseMailClient>()MailKit 客户端有状态(连接池)
SmsTransientAddTransient<ISMS, AliyunSmsService>()遗留,直接 AddTransient

Provider 构造函数的工厂委托

Provider 构造函数是 internal,DI 容器无法直接激活。注册时用工厂委托显式构造,绕过可见性限制:

services.AddIntegrationProviderCapability<IPaymentProvider, StripePaymentProvider>(
StripeProviderDescriptor.Instance,
serviceProvider => new StripePaymentProvider( // ① 工厂委托显式 new
serviceProvider.GetRequiredService<StripeHttpClient>(),
serviceProvider.GetRequiredService<IStripeConfigProvider>(),
serviceProvider.GetRequiredService<ILogger<StripePaymentProvider>>()));

单 Provider 兼容 vs 多 Provider 路由

registerLegacyAlias 参数控制 Provider 注册到能力接口的方式,决定了消费者如何解析 Provider。

单 Provider 模式(registerLegacyAlias = true

默认 true,Provider 同时注册为 TImplementation(按 ID 索引)和能力接口 TCapability(直接可注入)。消费者可直接注入能力接口,无需 Resolver:

// DI 注册(默认 registerLegacyAlias = true)
services.AddBitzsoftStripePayment(options => { ... });
// 消费者——直接注入 IPaymentProvider
public class CheckoutService(IPaymentProvider payment) // ① 单 Provider,直接注入
{
public async Task Pay() => await payment.CreateOrderAsync(...);
}

多 Provider 模式(registerLegacyAlias = false

注册多个同类 Provider 时,能力接口的直接注入会产生歧义。此时用 IIntegrationProviderResolver<TCapability> 按稳定 Provider ID 解析:

// DI 注册——多个支付渠道,禁用 legacy alias
services.AddBitzsoftStripePayment(options => { ... });
services.AddBitzsoftAlipayPayment(options => { ... });
// 消费者——用 Resolver 按需解析
public class CheckoutService(IIntegrationProviderResolver<IPaymentProvider> resolver)
{
public async Task Pay(string providerId)
{
// ① 按稳定 ID 解析 Provider
var provider = resolver.GetRequired(providerId); // "stripe" 或 "alipay"
await provider.CreateOrderAsync(...);
}
}

Stripe 的混合用法

Stripe 注册了两个能力(支付 + Webhook 验签),其中 Webhook 验签显式禁用 legacy alias 避免与支付接口冲突:

services.AddIntegrationProviderCapability<IPaymentProvider, StripePaymentProvider>(
StripeProviderDescriptor.Instance,
serviceProvider => new StripePaymentProvider(...));
// ① registerLegacyAlias 默认 true——支付能力可直接注入
services.AddIntegrationProviderCapability<IWebhookVerifier, StripeWebhookVerifier>(
StripeProviderDescriptor.Instance,
serviceProvider => new StripeWebhookVerifier(...),
registerLegacyAlias: false); // ② 禁用——避免与其它厂商 WebhookVerifier 冲突

聚合 .All 包注册

.All 包是空程序集,仅含一个 ServiceCollectionExtensions,按配置节存在性驱动注册。消费者只需调用一次 AddBitzsoft{Domain}All(),传入 IConfiguration,包内自动注册配置中存在的所有厂商。

工作原理

Payment.All/ServiceCollectionExtensions.cs
public static IServiceCollection AddBitzsoftPaymentAll(
this IServiceCollection services,
IConfiguration configuration,
string sectionKey = "Payment")
{
var section = configuration.GetSection(sectionKey);
// ① 配置节存在才注册——GetSection().Exists() 检查
if (section.GetSection("Alipay").Exists())
services.AddBitzsoftAlipayPayment(configuration, $"{sectionKey}:Alipay");
if (section.GetSection("WeChatPay").Exists())
services.AddBitzsoftWeChatPayPayment(configuration, $"{sectionKey}:WeChatPay");
if (section.GetSection("Stripe").Exists())
services.AddBitzsoftStripePayment(configuration, $"{sectionKey}:Stripe");
return services;
}

FileStorage.All 的泛型封装

FileStorage 有 12 个厂商,重复的 if (Exists()) 样板被提取成私有辅助方法:

RegisterIfPresent(
section, "Aliyun", configure => services.AddBitzsoftAliyunOssFileStorage(configure));
RegisterIfPresent(
section, "Aws", configure => services.AddBitzsoftAwsS3FileStorage(configure));
// ... 其余 10 个厂商
// 辅助方法
static void RegisterIfPresent(
IConfiguration section, string providerName,
Action<IConfigurationSection> register)
{
var provider = section.GetSection(providerName);
if (provider.Exists())
register(provider);
}

完整注册示例

单 Provider 场景

Program.cs
var builder = WebApplication.CreateBuilder(args);
// ① 注册 Core(Provider 目录与解析器)
builder.Services.AddBitzsoftIntegrationCore();
// ② 注册单个支付渠道——可直接注入 IPaymentProvider
builder.Services.AddBitzsoftStripePayment(builder.Configuration.GetSection("Payment:Stripe"));
var app = builder.Build();
// 消费
app.MapPost("/pay", async (IPaymentProvider payment) =>
await payment.CreateOrderAsync(new PaymentOrderRequest { ... }));

多 Provider 场景

Program.cs
var builder = WebApplication.CreateBuilder(args);
// ① 注册 Core
builder.Services.AddBitzsoftIntegrationCore();
// ② 聚合注册——配置中存在的厂商全部注册
builder.Services.AddBitzsoftPaymentAll(builder.Configuration);
var app = builder.Build();
// 消费——用 Resolver 按稳定 ID 解析
app.MapPost("/pay", async (
string providerId,
IIntegrationProviderResolver<IPaymentProvider> resolver) =>
{
var provider = resolver.GetRequired(providerId); // "stripe" / "alipay" / "wechatpay"
return await provider.CreateOrderAsync(new PaymentOrderRequest { ... });
});

对应的 appsettings.json

{
"Payment": {
"Stripe": { "SecretKey": "sk_live_xxx", "WebhookSecret": "whsec_xxx" },
"Alipay": { "AppId": "2021xxx", "PrivateKey": "..." }
}
}

注册内容清单

一个完整的厂商注册通常包含四项:

AddBitzsoft{Vendor}{Domain}()

命名 HttpClient
+ AddRequestLogging

Configure<Options>
配置绑定 + 校验

ConfigProvider
TryAddSingleton

Provider 能力
AddIntegrationProviderCapability

以 Stripe 为例,这四项的对应代码:

public static IServiceCollection AddBitzsoftStripePayment(
this IServiceCollection services, Action<StripeOptions> configure)
{
var options = new StripeOptions();
configure(options);
services.AddHttpClient(options.HttpClientName).AddRequestLogging(options.HttpClientName); // ① HttpClient
services.Configure(configure); // ② Options
services.TryAddSingleton<IStripeConfigProvider, StripeConfigProvider>(); // ③ ConfigProvider
RegisterProvider(services); // ④ Provider 能力
return services;
}

相关约定

100%

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