Skip to content
Bitzsoft.Integrationsbitzsoft.integrations

Guide

单厂商消费指南

只接入一家厂商时如何安装、配置、注册、注入能力接口并处理 Result,含支付宝完整可运行示例。

Last updated

当你确定只用一家厂商,且短期内不会扩到第二家,就走「单厂商消费」路线。它的特点是:装一个厂商包、注册一次、直接注入能力接口。比多厂商路由少了 Resolver 这层,代码更直接。

这篇指南用 Payment.Alipay(支付宝) 做完整可运行示例,同样的模式适用于任何域的单厂商消费(FileStorage.Oss、AI.OpenAI、eSign.Esign……)。

单厂商消费四步

① 安装厂商包

② 配置 Options

③ 注册服务
AddBitzsoft{Vendor}{Domain}()

④ 注入能力接口
直接用 IPaymentProvider

调用方法 + 处理 Result

四步固定,业务逻辑全部写在第 4 步之后。换厂商时只改前两步(换包、换配置),后两步的代码一行不动。

1. 安装厂商包

只装你要用的那一家,不用装聚合包。包的传递依赖会自动带齐抽象层、Core、Compatibility、RequestLogging。

Terminal window
dotnet new web -n MyShop
cd MyShop
# ① 装支付宝支付包(传递依赖自动带齐其余)
dotnet add package Bitzsoft.Integrations.Payment.Alipay

2. 配置 Options

每个厂商包对应一个配置节,节名默认就是厂商名(如 Alipay)。密钥不要进 Git,用 user-secrets 或环境变量管理。

Terminal window
# ① 密钥进 user-secrets,不进代码库
dotnet user-secrets init
dotnet user-secrets set "Alipay:AppId" "2021000..."
dotnet user-secrets set "Alipay:AppPrivateKey" "MIIEvQIBADANB..." # PEM 格式
dotnet user-secrets set "Alipay:AlipayPublicKey" "MIIBIjANBg..."
dotnet user-secrets set "Alipay:NotifyUrl" "https://your-domain.com/callback/alipay"

等价的 appsettings.json(生产用环境变量覆盖敏感字段):

{
"Alipay": {
"AppId": "2021000...",
"AppPrivateKey": "MIIEvQIBADANB...",
"AlipayPublicKey": "MIIBIjANBg...",
"Gateway": "https://openapi.alipay.com/gateway.do",
"NotifyUrl": "https://your-domain.com/callback/alipay",
"SignType": "RSA2",
"Timeout": "00:00:30"
}
}

配置字段与 AlipayOptions 一一对应。GatewaySignTypeTimeout 有默认值,可不配;AppId / AppPrivateKey / AlipayPublicKey 必填,缺失会在首次请求时抛 PaymentException

3. 注册服务

调用厂商包提供的 AddBitzsoft{厂商}{域}() 扩展方法。这会自动注册命名 HttpClient 并挂上请求审计日志。

Program.cs
using Bitzsoft.Integrations.Payment;
using Bitzsoft.Integrations.Payment.Models;
var builder = WebApplication.CreateBuilder(args);
// ① 一行注册:自动挂载 HttpClient + RequestLogHandler 审计脱敏
builder.Services.AddBitzsoftAlipayPayment(builder.Configuration.GetSection("Alipay"));
var app = builder.Build();
app.Run();

注册内部完成的事:绑定 AlipayOptions、注册命名 HttpClient(名为 AlipayPaymentProvider)并挂 AddRequestLogging、注册 IAlipayConfigProvider、把 AlipayPaymentProvider 作为 IPaymentProvider 能力提交到目录。

4. 注入能力接口并使用

直接注入 IPaymentProvider,不用关心后面是哪家厂商。所有方法返回 PaymentResult<T>,不抛业务异常给调用方。

// Program.cs —— 下单端点
app.MapPost("/api/pay", async (
IPaymentProvider payment, // ① 直接注入能力接口
PaymentOrderRequest request) =>
{
// ② 调用方法,换厂商时这段代码不动
var result = await payment.CreateOrderAsync(request);
// ③ 统一处理 Result,不写 try/catch
return result.IsSuccess
? Results.Ok(result.Data)
: Results.BadRequest(new { result.ErrorCode, result.ErrorMessage });
});
// 查询订单状态
app.MapGet("/api/pay/status/{outTradeNo}", async (
string outTradeNo,
IPaymentProvider payment) =>
{
var result = await payment.QueryStatusAsync(outTradeNo);
if (!result.IsSuccess)
return Results.BadRequest(new { result.ErrorCode, result.ErrorMessage });
var data = result.Data!;
return Results.Ok(new
{
data.OutTradeNo,
data.TradeNo,
Status = data.Status.ToString(),
data.PaidAmount,
});
});
// 回调验签
app.MapPost("/callback/alipay", async (HttpContext ctx, IPaymentProvider payment) =>
{
var body = await new StreamReader(ctx.Request.Body).ReadToEndAsync();
var payload = new CallbackPayload
{
Body = body,
QueryString = ctx.Request.QueryString.Value,
};
var result = await payment.VerifyCallbackAsync(payload);
if (!result.IsSuccess)
return Results.Text("fail");
var data = result.Data!;
Console.WriteLine($"订单 {data.OutTradeNo} 支付 {data.PaidAmount / 100m:F2} 元");
return Results.Text("success"); // ① 必须返回 "success",否则支付宝会重复通知
});

处理 Result 的标准模式

所有域的 Result<T> 结构一致:IsSuccess / Data / ErrorCode / ErrorMessage。消费侧不写 try/catch,统一用 if (!result.IsSuccess) 分支。

await provider.XxxAsync()

返回 Result

IsSuccess?

读 result.Data

读 result.ErrorCode
读 result.ErrorMessage

按错误码降级 / 重试 / 提示

常见错误码:

ErrorCode含义建议
HTTP_ERROR网络层失败(超时、DNS、连接拒绝)重试或告警
SIGN_VERIFY_FAILED回调签名验证失败检查公钥配置,拒绝处理
厂商业务码(如支付宝 ACQ.*厂商返回的业务错误按厂商文档处理
UNSUPPORTED_SCENE请求的支付场景不支持检查 Scene 枚举值

完整可运行示例

下面是一个最小完整应用,装包、配置、注册、下单、查询全在一个 Program.cs 里。

Terminal window
dotnet new web -n MyShop && cd MyShop
dotnet add package Bitzsoft.Integrations.Payment.Alipay
Program.cs
using Bitzsoft.Integrations.Payment;
using Bitzsoft.Integrations.Payment.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddBitzsoftAlipayPayment(builder.Configuration.GetSection("Alipay")); // ① 注册
var app = builder.Build();
app.MapPost("/api/pay", async (IPaymentProvider payment, PaymentOrderRequest req) => // ② 注入
{
var result = await payment.CreateOrderAsync(req); // ③ 调用
return result.IsSuccess ? Results.Ok(result.Data) : Results.BadRequest(result.ErrorMessage); // ④ 处理
});
app.Run();

发起一笔电脑网站支付:

Terminal window
curl -X POST http://localhost:5000/api/pay \
-H "Content-Type: application/json" \
-d '{
"outTradeNo": "ORDER-20260801-001",
"totalAmount": 100,
"subject": "测试商品",
"scene": "Web"
}'

响应里的 payUrl 就是支付宝收银台跳转地址。

{
"isSuccess": true,
"data": {
"outTradeNo": "ORDER-20260801-001",
"payUrl": "https://openapi.alipay.com/gateway.do?..."
}
}

何时升级到多厂商路由

单厂商模式在以下任一情况出现时,建议切到多厂商路由

  • 业务需要接入第二家厂商(如同时支持支付宝和微信)。
  • 需要按租户、地区或灰度策略动态切换厂商。
  • 想在测试环境用沙箱、生产用正式环境,且通过 Provider ID 切换。

升级很平滑:把直接注入 IPaymentProvider 换成注入 IIntegrationProviderResolver<IPaymentProvider>,调用前多一步 resolver.GetRequired(providerId)。业务方法(CreateOrderAsync 等)和 Result 处理代码原样保留。

下一步

100%

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