命名与可见性约定定义了连接器库的物理边界:哪些类型对消费者公开、哪些是内部实现细节、DI 扩展方法叫什么名字。这些约定保证跨域一致性,也让消费者只需学习一套规则即可理解所有 Provider。
命名空间分层
全库遵循固定的四层命名空间约定,对应三层包结构加上 DI 扩展所在的 Microsoft.Extensions.DependencyInjection。
Bitzsoft.Integrations.{Domain} // ① 抽象层:接口、DTO、异常Bitzsoft.Integrations.{Domain}.{Vendor} // ② 实现层:Options、Provider、ConfigProvider 接口Bitzsoft.Integrations.{Domain}.{Vendor}.Internal // ③ 内部层:HttpClient、签名器、常量、MapperMicrosoft.Extensions.DependencyInjection // ④ DI 扩展:ServiceCollectionExtensions以 Payment.Stripe 为例:
// ① 抽象层——契约namespace Bitzsoft.Integrations.Payment; // IPaymentProvider, PaymentResult<T>, PaymentException
// ② 实现层——配置与 Providernamespace Bitzsoft.Integrations.Payment.Stripe; // StripeOptions, StripePaymentProvider, IStripeConfigProvider
// ③ 内部层——协议适配细节namespace Bitzsoft.Integrations.Payment.Stripe.Internal; // StripeHttpClient, StripeSigner
// ④ DI 扩展——消费者入口namespace Microsoft.Extensions.DependencyInjection; // StripeServiceCollectionExtensions嵌套域的命名空间
Finance 域包含 Invoice、Tax、Payroll 三个子域,命名空间多一层:
Bitzsoft.Integrations.Finance.Invoice.Nuonuo // ② 实现层Bitzsoft.Integrations.Finance.Invoice.Nuonuo.Internal // ③ 内部层类型可见性矩阵
下表定义每个类型角色应有的访问修饰符。这是全库统一约定,新增 Provider 必须遵守。
| 类型角色 | 可见性 | 示例 |
|---|---|---|
| 抽象层接口 | public | IPaymentProvider |
| DTO / 请求响应模型 | public | PaymentOrderRequest |
| 域异常 | public | PaymentException |
| 域 Result 包装 | public sealed | PaymentResult<T> |
| 厂商 Options | public sealed | StripeOptions |
| ConfigProvider 接口 | public | IStripeConfigProvider |
| Provider 实现 | public sealed + internal 构造函数 | StripePaymentProvider |
| HttpClient 封装 | internal sealed | StripeHttpClient |
| 签名器 / 验证器 | internal sealed | StripeSigner |
| 常量类 | internal sealed | DingTalkConstants |
| Options 验证器 | internal sealed | DingTalkOptionsValidator |
| ModelMapper | internal sealed | DingTalkModelMapper |
| ConfigProvider 实现 | internal sealed | StripeConfigProvider |
| DI 扩展类 | public static | StripeServiceCollectionExtensions |
| Provider Descriptor | public sealed | StripeProviderDescriptor |
Provider 实现的特殊模式
Provider 类是 public sealed,但构造函数是 internal。这保证消费者无法 new 出实例,只能通过 DI 解析;同时实现类本身对 DI 容器可见(因为 DI 扩展方法用工厂委托构造)。
public sealed class StripePaymentProvider : IPaymentProvider{ private readonly StripeHttpClient _httpClient; private readonly IStripeConfigProvider _config;
// ① internal 构造函数——消费者无法直接 new,必须走 DI internal StripePaymentProvider( StripeHttpClient httpClient, IStripeConfigProvider config, ILogger<StripePaymentProvider> logger) { _httpClient = httpClient; _config = config; }}DI 方法命名
两种命名风格
// ① 推荐做法——Bitzsoft 前缀(Payment/Finance/FileStorage/TeamWork 等新域)services.AddBitzsoftStripePayment(options => { ... });services.AddBitzsoftDingTalkTeamWork(options => { ... });services.AddBitzsoftAwsS3FileStorage(options => { ... });
// ② 历史遗留——短名(仅 Sms 域)services.AddAliyunSms(options => { ... });services.AddTencentSms(options => { ... });命名公式
| 风格 | 公式 | 适用域 |
|---|---|---|
| 推荐 | AddBitzsoft{Vendor}{Domain}() | 除 Sms 外全部 |
| 遗留 | Add{Vendor}Sms() | Sms |
| 聚合 | AddBitzsoft{Domain}All() | 所有 .All 包 |
{Vendor} 是供应商品牌名(Stripe、DingTalk、AwsS3),{Domain} 是功能域名(Payment、TeamWork、FileStorage)。
方法重载约定
每个厂商至少提供两个重载——委托配置和 IConfiguration 绑定:
// ① 委托配置——适合代码内硬编码public static IServiceCollection AddBitzsoftStripePayment( this IServiceCollection services, Action<StripeOptions> configure)
// ② IConfiguration 绑定——适合从 appsettings.json 读取public static IServiceCollection AddBitzsoftStripePayment( this IServiceCollection services, IConfiguration configuration, string sectionKey = "Stripe")HttpClient 命名约定
命名 HttpClient 通过 nameof(ProviderClass) 生成,保证跨包唯一且可追溯:
public sealed class StripeOptions{ // ① HttpClientName 默认值用 nameof(ProviderClass) public string HttpClientName { get; set; } = nameof(StripePaymentProvider);}注册时用这个名字匹配 IHttpClientFactory.CreateClient():
services.AddHttpClient(options.HttpClientName).AddRequestLogging(options.HttpClientName);#region 块组织
类型实现按固定顺序组织 #region 块,保证阅读体验一致。文件级也用 #region Members 包裹 using 后的内容。
Provider 类的标准块顺序
public sealed class StripePaymentProvider : IPaymentProvider{ #region Constants // ① 协议常量:API 路径、字段名、前缀 private const string PathCheckoutSessions = "/v1/checkout/sessions";
#region Fields & Constructor // ② 私有只读字段 + internal 构造函数 private readonly StripeHttpClient _httpClient;
#region IPaymentProvider // ③ 接口实现(核心业务方法) public async Task<PaymentResult<PaymentOrderResult>> CreateOrderAsync(...) { }
#region Helpers // ④ 私有辅助方法:状态映射、JSON 解析 private static PaymentStatus MapPaymentStatus(string? status) { }}常用 region 块清单
| region 名称 | 内容 | 出现位置 |
|---|---|---|
Members | 文件级,包裹整个命名空间内容 | 所有文件 |
Constants | private const 协议值 | Provider、HttpClient |
Configuration | Options 类整体 | Options 文件 |
Properties | 公开属性 | Options、ConfigProvider |
Fields & Constructor | 私有字段 + 构造函数 | Provider、HttpClient |
Factory Methods | Success() / Fail() 工厂 | Result 类 |
Helpers | 私有辅助方法 | Provider、HttpClient |
IDisposable | Dispose() 实现 | 持有资源的类 |
Options 类的块组织
public sealed class StripeOptions{ #region Credentials // 凭据字段 public string SecretKey { get; set; } = string.Empty;
#region Endpoints // 端点配置 public string ApiBase { get; set; } = "https://api.stripe.com";
#region Timeouts & Limits // 超时与限制 public TimeSpan Timeout { get; set; } = TimeSpan.FromSeconds(30);
#region HttpClient // 客户端命名 public string HttpClientName { get; set; } = nameof(StripePaymentProvider);}Internal 文件夹结构
以 TeamWork.DingTalk/Internal/ 为最规范的参照,内部文件按职责分:
Internal/├── DingTalkHttpClient.cs // HTTP 封装├── DingTalkAuthHandler.cs // DelegatingHandler 令牌注入├── DingTalkOptionsValidator.cs // 配置校验├── DingTalkConstants.cs // 常量(可拆 partial)├── DingTalkModelMapper.cs // DTO ↔ 厂商模型映射(可拆 partial)└── JsonHelper.cs // JSON 辅助相关约定
- Options 配置与校验:Options 类可见性细节与校验器写法。
- DI 注册:扩展方法命名与
registerLegacyAlias语义。 - HttpClient 使用约定:HttpClientName 与三种客户端模式。
- 三层包模式:命名空间分层对应的物理包结构。