diff --git a/honey_box/common/env.js b/honey_box/common/env.js
index f192d080..13f1ca9d 100644
--- a/honey_box/common/env.js
+++ b/honey_box/common/env.js
@@ -11,8 +11,8 @@
// 测试环境配置 - .NET 10 后端
const testing = {
- baseUrl: 'https://app.zpc-xy.com/honey/api',
- // baseUrl: 'http://192.168.1.24:5238',
+ // baseUrl: 'https://app.zpc-xy.com/honey/api',
+ baseUrl: 'http://192.168.1.24:5238',
imageUrl: 'https://youdas-1308826010.cos.ap-shanghai.myqcloud.com',
loginPage: '',
wxAppId: ''
diff --git a/server/HoneyBox/src/HoneyBox.Admin/admin-web/src/api/business/config.ts b/server/HoneyBox/src/HoneyBox.Admin/admin-web/src/api/business/config.ts
index 2508c82b..472321d8 100644
--- a/server/HoneyBox/src/HoneyBox.Admin/admin-web/src/api/business/config.ts
+++ b/server/HoneyBox/src/HoneyBox.Admin/admin-web/src/api/business/config.ts
@@ -110,6 +110,8 @@ export interface WeixinPayMerchant {
cert_path?: string
/** 是否启用 */
is_enabled?: string
+ /** 支付回调地址 */
+ notify_url?: string
// ===== V3 新增字段 =====
diff --git a/server/HoneyBox/src/HoneyBox.Admin/admin-web/src/views/business/config/components/WeixinMerchantForm.vue b/server/HoneyBox/src/HoneyBox.Admin/admin-web/src/views/business/config/components/WeixinMerchantForm.vue
index 15d0d529..377f9cfa 100644
--- a/server/HoneyBox/src/HoneyBox.Admin/admin-web/src/views/business/config/components/WeixinMerchantForm.vue
+++ b/server/HoneyBox/src/HoneyBox.Admin/admin-web/src/views/business/config/components/WeixinMerchantForm.vue
@@ -100,6 +100,16 @@
V3版本使用更安全的RSA-SHA256签名和AES-GCM加密
+
+
+
+ 支付成功后微信回调通知的地址,留空使用默认值
+
+
diff --git a/server/HoneyBox/src/HoneyBox.Admin/admin-web/src/views/business/config/weixinpay.vue b/server/HoneyBox/src/HoneyBox.Admin/admin-web/src/views/business/config/weixinpay.vue
index 70342bf3..131efb30 100644
--- a/server/HoneyBox/src/HoneyBox.Admin/admin-web/src/views/business/config/weixinpay.vue
+++ b/server/HoneyBox/src/HoneyBox.Admin/admin-web/src/views/business/config/weixinpay.vue
@@ -89,6 +89,7 @@ const createDefaultMerchant = (): WeixinPayMerchant => ({
api_key: '',
cert_path: '',
is_enabled: '1',
+ notify_url: '',
// V3 字段默认值
pay_version: PayVersion.V2,
api_v3_key: '',
@@ -111,6 +112,7 @@ const loadData = async () => {
api_key: m.api_key || '',
cert_path: m.cert_path || '',
is_enabled: m.is_enabled || '1',
+ notify_url: m.notify_url || '',
// V3 字段回显
pay_version: m.pay_version || PayVersion.V2,
api_v3_key: m.api_v3_key || '',
diff --git a/server/HoneyBox/src/HoneyBox.Api/Controllers/NotifyController.cs b/server/HoneyBox/src/HoneyBox.Api/Controllers/NotifyController.cs
index 61753857..f6240b4c 100644
--- a/server/HoneyBox/src/HoneyBox.Api/Controllers/NotifyController.cs
+++ b/server/HoneyBox/src/HoneyBox.Api/Controllers/NotifyController.cs
@@ -1,4 +1,5 @@
using HoneyBox.Core.Interfaces;
+using HoneyBox.Model.Models.Payment;
using Microsoft.AspNetCore.Mvc;
namespace HoneyBox.Api.Controllers;
@@ -23,60 +24,63 @@ public class NotifyController : ControllerBase
}
///
- /// 微信支付回调接口
+ /// 微信支付回调接口(支持 V2 XML 和 V3 JSON 格式)
/// POST /api/notify/order_notify
/// 接收微信支付结果通知,处理订单状态更新
- /// Requirements: 2.1-2.9
///
- ///
- /// 微信支付回调流程:
- /// 1. 接收微信发送的XML格式回调数据
- /// 2. 验证签名确保数据安全
- /// 3. 根据订单类型(attach字段)路由到对应处理方法
- /// 4. 更新订单状态、扣减用户资产、触发抽奖等
- /// 5. 返回XML格式响应给微信
- ///
- /// 支持的订单类型(attach值):
- /// - user_recharge: 余额充值
- /// - order_yfs: 一番赏订单
- /// - order_lts: 擂台赏订单
- /// - order_zzs: 转转赏订单
- /// - order_flw: 福利屋订单
- /// - order_scs: 商城赏订单
- /// - order_wxs: 无限赏订单
- /// - order_fbs: 翻倍赏订单
- /// - order_ckj: 抽卡机订单
- /// - order_list_send: 发货运费
- ///
- /// XML格式响应
[HttpPost("order_notify")]
- [Consumes("application/xml", "text/xml")]
- [Produces("application/xml")]
public async Task OrderNotify()
{
try
{
- // 读取请求体中的XML数据
+ // 读取请求体
using var reader = new StreamReader(Request.Body);
- var xmlData = await reader.ReadToEndAsync();
+ var notifyBody = await reader.ReadToEndAsync();
- _logger.LogInformation("收到微信支付回调请求,数据长度: {Length}", xmlData?.Length ?? 0);
+ _logger.LogInformation("收到微信支付回调请求,数据长度: {Length}, ContentType: {ContentType}",
+ notifyBody?.Length ?? 0, Request.ContentType);
- // 调用服务处理回调
- var result = await _paymentNotifyService.HandleWechatNotifyAsync(xmlData ?? string.Empty);
+ // 提取 V3 回调请求头(如果存在)
+ WechatPayNotifyHeaders? headers = null;
+ if (Request.Headers.TryGetValue("Wechatpay-Timestamp", out var timestamp) &&
+ Request.Headers.TryGetValue("Wechatpay-Nonce", out var nonce) &&
+ Request.Headers.TryGetValue("Wechatpay-Signature", out var signature) &&
+ Request.Headers.TryGetValue("Wechatpay-Serial", out var serial))
+ {
+ headers = new WechatPayNotifyHeaders
+ {
+ Timestamp = timestamp.ToString(),
+ Nonce = nonce.ToString(),
+ Signature = signature.ToString(),
+ Serial = serial.ToString()
+ };
+ _logger.LogDebug("检测到 V3 回调请求头: Timestamp={Timestamp}, Serial={Serial}",
+ headers.Timestamp, headers.Serial);
+ }
+
+ // 调用服务处理回调(自动识别 V2/V3 格式)
+ var result = await _paymentNotifyService.HandleWechatNotifyAsync(notifyBody ?? string.Empty, headers);
_logger.LogInformation("微信支付回调处理完成: Success={Success}, Message={Message}",
result.Success, result.Message);
- // 返回XML响应给微信
- return Content(result.XmlResponse, "application/xml");
+ // 根据回调版本返回对应格式的响应
+ if (!string.IsNullOrEmpty(result.JsonResponse))
+ {
+ // V3 返回 JSON
+ return Content(result.JsonResponse, "application/json");
+ }
+ else
+ {
+ // V2 返回 XML
+ return Content(result.XmlResponse ?? "", "application/xml");
+ }
}
catch (Exception ex)
{
_logger.LogError(ex, "处理微信支付回调异常");
- // 即使发生异常,也返回成功响应,避免微信重复通知
- // 后续通过其他机制(如定时任务)处理失败的订单
+ // 返回成功响应,避免微信重复通知
var successResponse = "";
return Content(successResponse, "application/xml");
}
diff --git a/server/HoneyBox/src/HoneyBox.Api/HoneyBox.Api.csproj b/server/HoneyBox/src/HoneyBox.Api/HoneyBox.Api.csproj
index 9d149890..157d3a9c 100644
--- a/server/HoneyBox/src/HoneyBox.Api/HoneyBox.Api.csproj
+++ b/server/HoneyBox/src/HoneyBox.Api/HoneyBox.Api.csproj
@@ -1,4 +1,4 @@
-
+
net10.0
@@ -9,7 +9,7 @@
Linux
..\..
-
+
@@ -22,10 +22,27 @@
+
+
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+
diff --git a/server/HoneyBox/src/HoneyBox.Api/cert/apiclient_cert.pem b/server/HoneyBox/src/HoneyBox.Api/cert/apiclient_cert.pem
new file mode 100644
index 00000000..477e14fc
--- /dev/null
+++ b/server/HoneyBox/src/HoneyBox.Api/cert/apiclient_cert.pem
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIEPTCCAyWgAwIBAgIUcxO5U5v6gITLJb2T8GKiVbfA+AswDQYJKoZIhvcNAQEL
+BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT
+FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg
+Q0EwHhcNMjYwMTI1MDg1NjAxWhcNMzEwMTI0MDg1NjAxWjCBljETMBEGA1UEAwwK
+MTczODcyNTgwMTEbMBkGA1UECgwS5b6u5L+h5ZWG5oi357O757ufMUIwQAYDVQQL
+DDnmoZPlj7Dljr/lk4jlsLznlLXlrZDllYbliqHlt6XkvZzlrqTvvIjkuKrkvZPl
+t6XllYbmiLfvvIkxCzAJBgNVBAYTAkNOMREwDwYDVQQHDAhTaGVuWmhlbjCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANm51GTtTzcs/3m4WuCTppqv+QGk
+fYXaMzQakc1ZpG1gdmOjEYTZmzUNz6vnbrCbp+T5mow45o/c6/x2ChhZvQXj/ud+
+RGPKpySuT1hdQoq+l6OfNbS/u35iDGgjD1A1gbRNCG+cNaGpedruvvHMMdrBVCL2
+nvtprj5s5Vc+72nYtjLVCrELOzHNN8DaoJ3PkCSKGNLG2OwDXWe0wP+0KJ4GFPpN
+0OKEAY2vvEzOo1ENkBOn16mGBLwXnkn13J8hdih7KPcgmBeMHceDjCGfVo6Z+fES
+C7SIL8obtt9HMXRqkVuWPcl+y3UmAsujWIjIHxEQDUlyj2TB5s2CefVb330CAwEA
+AaOBuTCBtjAJBgNVHRMEAjAAMAsGA1UdDwQEAwID+DCBmwYDVR0fBIGTMIGQMIGN
+oIGKoIGHhoGEaHR0cDovL2V2Y2EuaXRydXMuY29tLmNuL3B1YmxpYy9pdHJ1c2Ny
+bD9DQT0xQkQ0MjIwRTUwREJDMDRCMDZBRDM5NzU0OTg0NkMwMUMzRThFQkQyJnNn
+PUhBQ0M0NzFCNjU0MjJFMTJCMjdBOUQzM0E4N0FEMUNERjU5MjZFMTQwMzcxMA0G
+CSqGSIb3DQEBCwUAA4IBAQCDOzEAS8OtTib+gRbYRDMw3mZ/dRR7RYuE8d1Rxf2y
+Xgv+C7NoHAFHxhoKmWGw9ImOMXM4YViHAWlkEZHqndF5ETNne2wl6X8wYpQIr1a1
+U0BlyxKOvgRquikPZp6mE2tOIxj6P2tngu2o9wljt7kuzDHsjdr1to4Omom1i514
+EgU2GoI37YgGIEeSy5c3h0j1vSQKy+fuKZKFWxPX1oOMTwVJFqtS/nrPBPftNMsf
+fIXBXjbKaLrjyBJiV/fD84nPENgOgkdnGp6/WaVy3kNydosTNINL4Es+0pUTTm9z
+EXRNzOxfvpYxGFGJyVEZmGwAOw/IVePN+J38FbSVyHyC
+-----END CERTIFICATE-----
diff --git a/server/HoneyBox/src/HoneyBox.Api/cert/apiclient_key.pem b/server/HoneyBox/src/HoneyBox.Api/cert/apiclient_key.pem
new file mode 100644
index 00000000..43d3e85b
--- /dev/null
+++ b/server/HoneyBox/src/HoneyBox.Api/cert/apiclient_key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDZudRk7U83LP95
+uFrgk6aar/kBpH2F2jM0GpHNWaRtYHZjoxGE2Zs1Dc+r526wm6fk+ZqMOOaP3Ov8
+dgoYWb0F4/7nfkRjyqckrk9YXUKKvpejnzW0v7t+YgxoIw9QNYG0TQhvnDWhqXna
+7r7xzDHawVQi9p77aa4+bOVXPu9p2LYy1QqxCzsxzTfA2qCdz5AkihjSxtjsA11n
+tMD/tCieBhT6TdDihAGNr7xMzqNRDZATp9ephgS8F55J9dyfIXYoeyj3IJgXjB3H
+g4whn1aOmfnxEgu0iC/KG7bfRzF0apFblj3Jfst1JgLLo1iIyB8REA1Jco9kwebN
+gnn1W999AgMBAAECggEATpKsnruxgcUAcYnhafh/AIYPA9O75OlI3z3TblsyZrKQ
+Jwb7VIk/ZNcWIgCERsH1xkF5z67dLf/ZPiPPItiHya9tF1fPEIBa73bkdYw6bl23
+1bmoJRGodUSnG5HDffvBUjMWn0itZikGK8dLK3G4cCyi03dTCoIp+qdL4L96oSSE
+uHChH9jSq2+LiR4P32GrSWO6z8dwS+2vonaepQoHbfEFbuSjNrdv78kt1DhJeY6u
+ZkRqDR/T10+BLZX2gxuQ0ddH/YgeO2E6K99a7YWCGGVH7C0U4T2ZR5HJjAgxGsQ6
+8KQvzXwhHYNyxkpBaRCO6dogofVe1PXxW/Xi3rlJFQKBgQDvpCpDB8P5RUvq2Us/
+7GnmeuwWuO8T5byNpTSBHNwVH/vCQqvorFPYJXicvk/1yjriXwiPnfw0j11uaZsd
+1ZJxQeXiS0ASsrihu5m6AxisFOU0cJNpl6njW5Y2JQAZdgg4APDzXfSLp2Ev5h6K
+vuRMfmmse0gWeWDFUZEamInyVwKBgQDolq8XtfyDAZPEPldJmbVMiuBu7nJLDhHz
+mL0tU5dPiKSduqFEbcuOSPREZb2wIw5MR1gsuCPk5rwx69DNY2Oztz+VcK3Vo1oN
+4MufsPXKOTOSbdV8JjcVLxHxn+b8QIbDribncsg15I7n8P3wcZ640WWGom/H9spZ
+HC3//DEgSwKBgHkRwWA4DiRjhCVUPpY/BImy1I/uQqsUyBvvuQT55Z6ul+ze7icQ
+2RM8ayEVbSRKVVGEnbihIogTXiqoI/wAqImbt16KkgZgULM1Kkc1xUM7E0lZDsCs
+JOJ+pPcZ3mD+psxUfWcWsrPTjmA6rHeAVarnus+vQQ5JqEBIIz0Cj77lAoGBAJPj
+lAuIjLmkHBfw58GFubCksVX3ybaNiL6SRN94QkKxCLK+A2KmSYL8QkznQDip4aKA
+zsEIiNI4IDvBzK973d5cy1IzJmUsC8u9PtwYQgDGZFNcAR2Ckw2mM0umt9F3Gfl8
+V4JdCo6x+GfkZSMoq5qqklqMGHVWJ42HjHwzF+2HAoGAE3FjmHDw5eGqu2aFNDUD
+ulh+ikSkjH+1hLKR6amDqssCackET1gYIRnUXAQO7FKg/W96enffg7jZF+7E3OOT
+TQo/obfpQPVaGKJ0CmqlSNyarZD6BFpBJKEiT8mlgkZ6XoyXZaAR2FjieoGd8xxi
+1mIIXb9fbcQO1lIhXnHlZUQ=
+-----END PRIVATE KEY-----
diff --git a/server/HoneyBox/src/HoneyBox.Api/cert/pub_key.pem b/server/HoneyBox/src/HoneyBox.Api/cert/pub_key.pem
new file mode 100644
index 00000000..d32530b0
--- /dev/null
+++ b/server/HoneyBox/src/HoneyBox.Api/cert/pub_key.pem
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0KeKMd6Yxovf4kPI0c1Q
+Islyq9fi/Wg60dodzPNkRRoraqmqbbW7uQcKHkHvIZi5Z9fK8SGkezyhcjiR3o8z
+uwnH5QiFuMw6P+1XB1koFfbxxCc6Eh0iuRI5BqNfyRwXwn9wIEUNwfF/SAPJGTkk
+hCzViil3tOmnJDMxQUJitt4RsnL6BvQ3afWcm7oqt7MLlcIhIW8jAsSFeWPuZcW5
+Hj+o2udrTUaTRkw7AEsHr9xyePhsqYjGxbi9fTlghkUYnRUNikSydtQoHbGHP70Q
+tz4HbPqH4gpsCqabPVuANFGH5a8uidOH3XKq2iPLggbPci1nFI8xMmHMaT88u/o5
+GQIDAQAB
+-----END PUBLIC KEY-----
diff --git a/server/HoneyBox/src/HoneyBox.Core/Services/OrderService.cs b/server/HoneyBox/src/HoneyBox.Core/Services/OrderService.cs
index 1f497c49..1344fb04 100644
--- a/server/HoneyBox/src/HoneyBox.Core/Services/OrderService.cs
+++ b/server/HoneyBox/src/HoneyBox.Core/Services/OrderService.cs
@@ -5,6 +5,7 @@ using HoneyBox.Model.Models;
using HoneyBox.Model.Models.Goods;
using HoneyBox.Model.Models.Lottery;
using HoneyBox.Model.Models.Order;
+using HoneyBox.Model.Models.Payment;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
@@ -18,6 +19,7 @@ public class OrderService : IOrderService
private readonly HoneyBoxDbContext _dbContext;
private readonly ILogger _logger;
private readonly ILotteryEngine _lotteryEngine;
+ private readonly IWechatPayService _wechatPayService;
// 抽奖赏品ID范围 [10, 33]
private static readonly int[] ShangPrizeIdRange = { 10, 33 };
@@ -28,11 +30,16 @@ public class OrderService : IOrderService
// 无限赏商品类型
private static readonly int[] InfiniteGoodsTypes = { 2, 8, 9, 10, 16, 17 };
- public OrderService(HoneyBoxDbContext dbContext, ILogger logger, ILotteryEngine lotteryEngine)
+ public OrderService(
+ HoneyBoxDbContext dbContext,
+ ILogger logger,
+ ILotteryEngine lotteryEngine,
+ IWechatPayService wechatPayService)
{
_dbContext = dbContext;
_logger = logger;
_lotteryEngine = lotteryEngine;
+ _wechatPayService = wechatPayService;
}
#region 订单金额计算
@@ -1034,21 +1041,37 @@ public class OrderService : IOrderService
if (paymentResult.Price > 0)
{
- // 需要微信支付
- // 注意:实际的微信支付参数生成需要调用微信支付API
- // 这里返回占位数据,实际实现需要集成微信支付SDK
+ // 需要微信支付 - 调用微信支付服务
+ var payRequest = new WechatPayRequest
+ {
+ UserId = userId,
+ OrderNo = orderNum,
+ Amount = paymentResult.Price,
+ Body = goods.Title,
+ Attach = $"order_{goods.Type}"
+ };
+
+ var payResult = await _wechatPayService.CreatePaymentAsync(payRequest);
+
+ if (payResult.Status != 1 || payResult.Data == null)
+ {
+ // 支付创建失败,回滚事务
+ await transaction.RollbackAsync();
+ throw new InvalidOperationException(payResult.Msg ?? "创建支付订单失败");
+ }
+
response = new OrderBuyResponseDto
{
Status = 1, // 需要支付
OrderNum = orderNum,
Res = new WechatPayParamsDto
{
- AppId = "", // 从配置获取
- TimeStamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(),
- NonceStr = Guid.NewGuid().ToString("N"),
- Package = $"prepay_id=placeholder_{orderNum}",
- SignType = "RSA",
- PaySign = "" // 需要实际签名
+ AppId = payResult.Data.AppId,
+ TimeStamp = payResult.Data.TimeStamp,
+ NonceStr = payResult.Data.NonceStr,
+ Package = payResult.Data.Package,
+ SignType = payResult.Data.SignType,
+ PaySign = payResult.Data.PaySign
}
};
}
@@ -1453,21 +1476,37 @@ public class OrderService : IOrderService
if (paymentResult.Price > 0)
{
- // 需要微信支付
- // 注意:实际的微信支付参数生成需要调用微信支付API
- // 这里返回占位数据,实际实现需要集成微信支付SDK
+ // 需要微信支付 - 调用微信支付服务
+ var payRequest = new WechatPayRequest
+ {
+ UserId = userId,
+ OrderNo = orderNum,
+ Amount = paymentResult.Price,
+ Body = goods.Title,
+ Attach = $"infinite_{goods.Type}"
+ };
+
+ var payResult = await _wechatPayService.CreatePaymentAsync(payRequest);
+
+ if (payResult.Status != 1 || payResult.Data == null)
+ {
+ // 支付创建失败,回滚事务
+ await transaction.RollbackAsync();
+ throw new InvalidOperationException(payResult.Msg ?? "创建支付订单失败");
+ }
+
response = new OrderBuyResponseDto
{
Status = 1, // 需要支付
OrderNum = orderNum,
Res = new WechatPayParamsDto
{
- AppId = "", // 从配置获取
- TimeStamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(),
- NonceStr = Guid.NewGuid().ToString("N"),
- Package = $"prepay_id=placeholder_{orderNum}",
- SignType = "RSA",
- PaySign = "" // 需要实际签名
+ AppId = payResult.Data.AppId,
+ TimeStamp = payResult.Data.TimeStamp,
+ NonceStr = payResult.Data.NonceStr,
+ Package = payResult.Data.Package,
+ SignType = payResult.Data.SignType,
+ PaySign = payResult.Data.PaySign
}
};
}
diff --git a/server/HoneyBox/src/HoneyBox.Core/Services/WechatPayConfigService.cs b/server/HoneyBox/src/HoneyBox.Core/Services/WechatPayConfigService.cs
index 49e913dd..ee7854e5 100644
--- a/server/HoneyBox/src/HoneyBox.Core/Services/WechatPayConfigService.cs
+++ b/server/HoneyBox/src/HoneyBox.Core/Services/WechatPayConfigService.cs
@@ -1,373 +1,327 @@
+using System.Text.Json;
+using System.Text.Json.Serialization;
using HoneyBox.Core.Interfaces;
+using HoneyBox.Model.Data;
using HoneyBox.Model.Models.Payment;
+using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
-using Microsoft.Extensions.Options;
namespace HoneyBox.Core.Services;
///
/// 微信支付配置服务实现
-/// 负责处理多商户配置、订单前缀匹配等逻辑
+/// 从数据库读取配置,支持多商户、多小程序
///
public class WechatPayConfigService : IWechatPayConfigService
{
- private readonly WechatPaySettings _settings;
+ private readonly HoneyBoxDbContext _dbContext;
+ private readonly IRedisService _redisService;
private readonly ILogger _logger;
private readonly Random _random = new();
- // 订单前缀常量
- private const string MH_PREFIX = "MH_";
- private const string FH_PREFIX = "FH_";
- private const int MERCHANT_PREFIX_LENGTH = 3;
- private const int MINIPROGRAM_PREFIX_LENGTH = 2;
- private const int TOTAL_PREFIX_LENGTH = MERCHANT_PREFIX_LENGTH + MINIPROGRAM_PREFIX_LENGTH;
+ private const string MERCHANTS_CACHE_KEY = "wechatpay:merchants";
+ private const string MINIPROGRAMS_CACHE_KEY = "wechatpay:miniprograms";
+ private static readonly TimeSpan CACHE_DURATION = TimeSpan.FromMinutes(5);
public WechatPayConfigService(
- IOptions settings,
+ HoneyBoxDbContext dbContext,
+ IRedisService redisService,
ILogger logger)
{
- _settings = settings.Value;
+ _dbContext = dbContext;
+ _redisService = redisService;
_logger = logger;
}
- ///
- public WechatPayMerchantConfig GetDefaultConfig()
+ private async Task> LoadMerchantsAsync()
{
- return _settings.DefaultMerchant;
- }
-
- ///
- public WechatPayMerchantConfig GetMerchantByOrderNo(string orderNo)
- {
- if (string.IsNullOrEmpty(orderNo))
+ var cachedJson = await _redisService.GetStringAsync(MERCHANTS_CACHE_KEY);
+ if (!string.IsNullOrEmpty(cachedJson))
{
- return _settings.DefaultMerchant;
- }
-
- // 检查是否是MH_或FH_开头的订单号
- if (!orderNo.StartsWith(MH_PREFIX) && !orderNo.StartsWith(FH_PREFIX))
- {
- // 尝试直接匹配订单前缀
- foreach (var m in _settings.Merchants)
+ try
{
- if (!string.IsNullOrEmpty(m.OrderPrefix) &&
- orderNo.StartsWith(m.OrderPrefix))
- {
- return m;
- }
+ var cached = JsonSerializer.Deserialize>(cachedJson);
+ if (cached != null && cached.Count > 0) return cached;
}
- return _settings.DefaultMerchant;
+ catch { }
}
- // 提取订单前缀信息
- var prefixInfo = ExtractOrderPrefix(orderNo);
- if (prefixInfo == null)
+ var merchants = new List();
+ try
{
- return _settings.DefaultMerchant;
- }
+ var settingConfig = await _dbContext.Configs
+ .Where(c => c.ConfigKey == "weixinpay_setting")
+ .Select(c => c.ConfigValue)
+ .FirstOrDefaultAsync();
- WechatPayMerchantConfig? merchant = null;
- string appId = string.Empty;
-
- // 优先根据小程序前缀获取配置
- if (!string.IsNullOrEmpty(prefixInfo.MiniprogramPrefix))
- {
- var miniprogramConfig = GetMiniprogramByPrefix(prefixInfo.MiniprogramPrefix);
- if (miniprogramConfig != null)
+ if (!string.IsNullOrEmpty(settingConfig))
{
- appId = miniprogramConfig.AppId;
-
- // 如果有商户前缀,使用指定商户
- if (!string.IsNullOrEmpty(prefixInfo.MerchantPrefix))
+ var setting = JsonSerializer.Deserialize(settingConfig, JsonOptions);
+ if (setting?.Merchants != null)
{
- merchant = GetMerchantByPrefix(prefixInfo.MerchantPrefix);
- }
-
- // 如果没有找到商户,从小程序关联的商户中选择
- if (merchant == null && miniprogramConfig.Merchants.Count > 0)
- {
- var associatedMerchants = _settings.Merchants
- .Where(m => miniprogramConfig.Merchants.Contains(m.MchId))
- .ToList();
-
- if (associatedMerchants.Count > 0)
+ foreach (var m in setting.Merchants.Where(x => x.IsEnabled == "1"))
{
- merchant = GetRandomMerchant(associatedMerchants);
+ merchants.Add(new WechatPayMerchantConfig
+ {
+ Name = m.Name ?? "",
+ MchId = m.MchId ?? "",
+ Key = m.ApiKey ?? "",
+ OrderPrefix = m.OrderPrefix ?? "",
+ PayVersion = m.PayVersion ?? "V2",
+ ApiV3Key = m.ApiV3Key,
+ CertSerialNo = m.CertSerialNo,
+ PrivateKeyPath = m.PrivateKeyPath,
+ WechatPublicKeyId = m.WechatPublicKeyId,
+ WechatPublicKeyPath = m.WechatPublicKeyPath,
+ NotifyUrl = !string.IsNullOrEmpty(m.NotifyUrl) ? m.NotifyUrl : "https://api.zfunbox.cn/api/notify"
+ });
}
}
}
- }
- // 如果没有通过小程序前缀获取到配置,则回退到商户前缀
- if (merchant == null && !string.IsNullOrEmpty(prefixInfo.MerchantPrefix))
- {
- merchant = GetMerchantByPrefix(prefixInfo.MerchantPrefix);
- }
+ var weixinpayConfig = await _dbContext.Configs
+ .Where(c => c.ConfigKey == "weixinpay")
+ .Select(c => c.ConfigValue)
+ .FirstOrDefaultAsync();
- // 如果还是没有找到,返回默认配置
- if (merchant == null)
- {
- return _settings.DefaultMerchant;
- }
-
- // 如果有小程序AppId,覆盖商户的AppId
- if (!string.IsNullOrEmpty(appId))
- {
- // 创建一个新的配置对象,避免修改原始配置
- return new WechatPayMerchantConfig
+ if (!string.IsNullOrEmpty(weixinpayConfig))
{
- Name = merchant.Name,
- MchId = merchant.MchId,
- AppId = appId,
- Key = merchant.Key,
- OrderPrefix = merchant.OrderPrefix,
- Weight = merchant.Weight,
- NotifyUrl = merchant.NotifyUrl,
- // V3 字段映射
- PayVersion = merchant.PayVersion,
- ApiV3Key = merchant.ApiV3Key,
- CertSerialNo = merchant.CertSerialNo,
- PrivateKeyPath = merchant.PrivateKeyPath,
- WechatPublicKeyId = merchant.WechatPublicKeyId,
- WechatPublicKeyPath = merchant.WechatPublicKeyPath
- };
- }
-
- return merchant;
- }
-
-
- ///
- public WechatPayMerchantConfig? GetMerchantByPrefix(string merchantPrefix)
- {
- if (string.IsNullOrEmpty(merchantPrefix))
- {
- return null;
- }
-
- return _settings.Merchants.FirstOrDefault(m =>
- !string.IsNullOrEmpty(m.OrderPrefix) &&
- m.OrderPrefix.Equals(merchantPrefix, StringComparison.OrdinalIgnoreCase));
- }
-
- ///
- public MiniprogramConfig? GetMiniprogramByPrefix(string miniprogramPrefix)
- {
- if (string.IsNullOrEmpty(miniprogramPrefix))
- {
- return null;
- }
-
- return _settings.Miniprograms.FirstOrDefault(m =>
- !string.IsNullOrEmpty(m.OrderPrefix) &&
- m.OrderPrefix.Equals(miniprogramPrefix, StringComparison.OrdinalIgnoreCase));
- }
-
- ///
- public MiniprogramConfig? GetMiniprogramByDomain(string domain)
- {
- if (string.IsNullOrEmpty(domain))
- {
- return GetDefaultMiniprogram();
- }
-
- foreach (var miniprogram in _settings.Miniprograms)
- {
- if (string.IsNullOrEmpty(miniprogram.Domain))
- {
- continue;
- }
-
- // 分割多个域名
- var domains = miniprogram.Domain.Split(',', StringSplitOptions.RemoveEmptyEntries);
- foreach (var d in domains)
- {
- var trimmedDomain = d.Trim();
- if (DomainMatch(trimmedDomain, domain))
+ var config = JsonSerializer.Deserialize(weixinpayConfig, JsonOptions);
+ if (config != null && !string.IsNullOrEmpty(config.MchId) && !merchants.Any(m => m.MchId == config.MchId))
{
- return miniprogram;
+ merchants.Add(new WechatPayMerchantConfig
+ {
+ Name = "默认商户",
+ MchId = config.MchId,
+ AppId = config.AppId ?? "",
+ Key = config.Keys ?? "",
+ OrderPrefix = "MYH",
+ PayVersion = "V2",
+ NotifyUrl = "https://api.zfunbox.cn/api/notify"
+ });
}
}
- }
- return GetDefaultMiniprogram();
- }
-
- ///
- public MiniprogramConfig? GetDefaultMiniprogram()
- {
- // 查找默认小程序配置
- var defaultMiniprogram = _settings.Miniprograms.FirstOrDefault(m => m.IsDefault);
-
- // 如果没有设置默认配置,返回第一个配置
- if (defaultMiniprogram == null && _settings.Miniprograms.Count > 0)
- {
- return _settings.Miniprograms[0];
- }
-
- return defaultMiniprogram;
- }
-
- ///
- public OrderPrefixInfo? ExtractOrderPrefix(string orderNo)
- {
- if (string.IsNullOrEmpty(orderNo))
- {
- return null;
- }
-
- // 检查是否是MH_或FH_开头
- if (!orderNo.StartsWith(MH_PREFIX) && !orderNo.StartsWith(FH_PREFIX))
- {
- return null;
- }
-
- // 提取MH_或FH_后的字符
- // 订单格式: MH_ABC12... 或 FH_ABC12...
- // 其中ABC是商户前缀(3位),12是小程序前缀(2位,可选)
- var prefixStart = 3; // "MH_" 或 "FH_" 的长度
-
- if (orderNo.Length < prefixStart + MERCHANT_PREFIX_LENGTH)
- {
- return null;
- }
-
- var result = new OrderPrefixInfo();
-
- // 提取商户前缀(前3位)
- result.MerchantPrefix = orderNo.Substring(prefixStart, MERCHANT_PREFIX_LENGTH);
-
- // 如果有足够长度,提取小程序前缀(后2位)
- if (orderNo.Length >= prefixStart + TOTAL_PREFIX_LENGTH)
- {
- result.MiniprogramPrefix = orderNo.Substring(
- prefixStart + MERCHANT_PREFIX_LENGTH,
- MINIPROGRAM_PREFIX_LENGTH);
- }
-
- return result;
- }
-
- ///
- public WechatPayMerchantConfig? GetRandomMerchant(IEnumerable merchants)
- {
- var merchantList = merchants.ToList();
-
- if (merchantList.Count == 0)
- {
- return null;
- }
-
- // 只有一个商户,直接返回
- if (merchantList.Count == 1)
- {
- return merchantList[0];
- }
-
- // 计算总权重
- var totalWeight = merchantList.Sum(m => m.Weight > 0 ? m.Weight : 1);
-
- // 生成随机数
- var randomWeight = _random.Next(1, totalWeight + 1);
-
- // 根据权重选择商户
- var currentWeight = 0;
- foreach (var merchant in merchantList)
- {
- var weight = merchant.Weight > 0 ? merchant.Weight : 1;
- currentWeight += weight;
-
- if (randomWeight <= currentWeight)
+ _logger.LogInformation("从数据库加载了 {Count} 个商户配置", merchants.Count);
+ if (merchants.Count > 0)
{
- return merchant;
+ await _redisService.SetStringAsync(MERCHANTS_CACHE_KEY, JsonSerializer.Serialize(merchants), CACHE_DURATION);
}
}
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "加载商户配置失败");
+ }
- // 默认返回第一个商户
- return merchantList[0];
+ return merchants;
}
- ///
- public (WechatPayMerchantConfig Merchant, string AppId) GetWxPayConfig()
+ private async Task> LoadMiniprogramsAsync()
{
- // 获取当前域名对应的小程序配置
- var miniprogram = GetDefaultMiniprogram();
- WechatPayMerchantConfig? merchant = null;
+ var cachedJson = await _redisService.GetStringAsync(MINIPROGRAMS_CACHE_KEY);
+ if (!string.IsNullOrEmpty(cachedJson))
+ {
+ try
+ {
+ var cached = JsonSerializer.Deserialize>(cachedJson);
+ if (cached != null && cached.Count > 0) return cached;
+ }
+ catch { }
+ }
+
+ var miniprograms = new List();
+ try
+ {
+ var settingConfig = await _dbContext.Configs
+ .Where(c => c.ConfigKey == "miniprogram_setting")
+ .Select(c => c.ConfigValue)
+ .FirstOrDefaultAsync();
+
+ if (!string.IsNullOrEmpty(settingConfig))
+ {
+ var setting = JsonSerializer.Deserialize(settingConfig, JsonOptions);
+ if (setting?.Miniprograms != null)
+ {
+ foreach (var m in setting.Miniprograms)
+ {
+ miniprograms.Add(new MiniprogramConfig
+ {
+ Name = m.Name ?? "",
+ AppId = m.AppId ?? "",
+ AppSecret = m.AppSecret ?? "",
+ OrderPrefix = m.OrderPrefix ?? "",
+ IsDefault = m.IsDefault == 1,
+ Merchants = m.Merchants ?? new List()
+ });
+ }
+ }
+ }
+
+ _logger.LogInformation("从数据库加载了 {Count} 个小程序配置", miniprograms.Count);
+ if (miniprograms.Count > 0)
+ {
+ await _redisService.SetStringAsync(MINIPROGRAMS_CACHE_KEY, JsonSerializer.Serialize(miniprograms), CACHE_DURATION);
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "加载小程序配置失败");
+ }
+
+ return miniprograms;
+ }
+
+ public WechatPayMerchantConfig GetDefaultConfig()
+ {
+ var merchants = LoadMerchantsAsync().GetAwaiter().GetResult();
+ return merchants.FirstOrDefault() ?? new WechatPayMerchantConfig();
+ }
+
+ public WechatPayMerchantConfig GetMerchantByOrderNo(string orderNo)
+ {
+ var merchants = LoadMerchantsAsync().GetAwaiter().GetResult();
+ var miniprograms = LoadMiniprogramsAsync().GetAwaiter().GetResult();
+
+ if (string.IsNullOrEmpty(orderNo) || merchants.Count == 0)
+ return GetDefaultConfig();
+
+ var miniprogram = miniprograms.FirstOrDefault(m => m.IsDefault) ?? miniprograms.FirstOrDefault();
+ WechatPayMerchantConfig? selectedMerchant = null;
+ string appId = miniprogram?.AppId ?? "";
- // 如果小程序配置了关联商户,从关联商户中随机选择一个
if (miniprogram != null && miniprogram.Merchants.Count > 0)
{
- var associatedMerchants = _settings.Merchants
- .Where(m => miniprogram.Merchants.Contains(m.MchId))
- .ToList();
-
+ var associatedMerchants = merchants.Where(m => miniprogram.Merchants.Contains(m.MchId)).ToList();
if (associatedMerchants.Count > 0)
{
- merchant = GetRandomMerchant(associatedMerchants);
+ selectedMerchant = GetRandomMerchant(associatedMerchants);
+ _logger.LogDebug("从小程序关联商户中选择: MchId={MchId}", selectedMerchant?.MchId);
}
}
- // 如果没有关联商户,则从所有商户中随机选择
- if (merchant == null && _settings.Merchants.Count > 0)
+ selectedMerchant ??= merchants.FirstOrDefault();
+ if (selectedMerchant == null) return new WechatPayMerchantConfig();
+
+ return new WechatPayMerchantConfig
{
- merchant = GetRandomMerchant(_settings.Merchants);
- }
-
- // 如果还是没有商户,使用默认商户
- merchant ??= _settings.DefaultMerchant;
-
- // 获取AppId - 优先使用小程序配置中的AppId
- var appId = miniprogram?.AppId ?? merchant.AppId;
-
- return (merchant, appId);
+ Name = selectedMerchant.Name,
+ MchId = selectedMerchant.MchId,
+ AppId = appId,
+ Key = selectedMerchant.Key,
+ OrderPrefix = selectedMerchant.OrderPrefix,
+ Weight = selectedMerchant.Weight,
+ NotifyUrl = selectedMerchant.NotifyUrl,
+ PayVersion = selectedMerchant.PayVersion,
+ ApiV3Key = selectedMerchant.ApiV3Key,
+ CertSerialNo = selectedMerchant.CertSerialNo,
+ PrivateKeyPath = selectedMerchant.PrivateKeyPath,
+ WechatPublicKeyId = selectedMerchant.WechatPublicKeyId,
+ WechatPublicKeyPath = selectedMerchant.WechatPublicKeyPath
+ };
+ }
+
+ public WechatPayMerchantConfig? GetMerchantByPrefix(string merchantPrefix)
+ {
+ if (string.IsNullOrEmpty(merchantPrefix)) return null;
+ var merchants = LoadMerchantsAsync().GetAwaiter().GetResult();
+ return merchants.FirstOrDefault(m => !string.IsNullOrEmpty(m.OrderPrefix) && m.OrderPrefix.Equals(merchantPrefix, StringComparison.OrdinalIgnoreCase));
+ }
+
+ public MiniprogramConfig? GetMiniprogramByPrefix(string miniprogramPrefix)
+ {
+ if (string.IsNullOrEmpty(miniprogramPrefix)) return null;
+ var miniprograms = LoadMiniprogramsAsync().GetAwaiter().GetResult();
+ return miniprograms.FirstOrDefault(m => !string.IsNullOrEmpty(m.OrderPrefix) && m.OrderPrefix.Equals(miniprogramPrefix, StringComparison.OrdinalIgnoreCase));
+ }
+
+ public MiniprogramConfig? GetMiniprogramByDomain(string domain) => GetDefaultMiniprogram();
+
+ public MiniprogramConfig? GetDefaultMiniprogram()
+ {
+ var miniprograms = LoadMiniprogramsAsync().GetAwaiter().GetResult();
+ return miniprograms.FirstOrDefault(m => m.IsDefault) ?? miniprograms.FirstOrDefault();
+ }
+
+ public OrderPrefixInfo? ExtractOrderPrefix(string orderNo)
+ {
+ if (string.IsNullOrEmpty(orderNo) || (!orderNo.StartsWith("MH_") && !orderNo.StartsWith("FH_")))
+ return null;
+ if (orderNo.Length < 6) return null;
+ return new OrderPrefixInfo
+ {
+ MerchantPrefix = orderNo.Substring(3, 3),
+ MiniprogramPrefix = orderNo.Length >= 8 ? orderNo.Substring(6, 2) : null
+ };
+ }
+
+ public WechatPayMerchantConfig? GetRandomMerchant(IEnumerable merchants)
+ {
+ var list = merchants.ToList();
+ if (list.Count == 0) return null;
+ if (list.Count == 1) return list[0];
+
+ var totalWeight = list.Sum(m => m.Weight > 0 ? m.Weight : 1);
+ var randomWeight = _random.Next(1, totalWeight + 1);
+ var currentWeight = 0;
+
+ foreach (var merchant in list)
+ {
+ currentWeight += merchant.Weight > 0 ? merchant.Weight : 1;
+ if (randomWeight <= currentWeight) return merchant;
+ }
+ return list[0];
+ }
+
+ public (WechatPayMerchantConfig Merchant, string AppId) GetWxPayConfig()
+ {
+ var merchant = GetMerchantByOrderNo("");
+ return (merchant, merchant.AppId);
}
- ///
public (WechatPayMerchantConfig? Merchant, string AppId) GetFixedWxPayConfig(string orderPrefix)
{
- // 获取当前域名对应的小程序配置
- var miniprogram = GetDefaultMiniprogram();
-
- // 尝试查找与订单前缀匹配的商户
var merchant = GetMerchantByPrefix(orderPrefix);
-
- // 如果没有找到匹配的商户,则使用随机选择
if (merchant == null)
{
var config = GetWxPayConfig();
return (config.Merchant, config.AppId);
}
-
- // 获取AppId - 优先使用小程序配置中的AppId
- var appId = miniprogram?.AppId ?? merchant.AppId;
-
- return (merchant, appId);
+ var miniprogram = GetDefaultMiniprogram();
+ return (merchant, miniprogram?.AppId ?? merchant.AppId);
}
- ///
- /// 检查域名是否匹配
- ///
- /// 配置中的域名模式
- /// 当前请求的域名
- /// 是否匹配
- private static bool DomainMatch(string pattern, string domain)
+ private static readonly JsonSerializerOptions JsonOptions = new() { PropertyNameCaseInsensitive = true };
+
+ private class DbWeixinPaySetting { [JsonPropertyName("merchants")] public List? Merchants { get; set; } }
+ private class DbMerchantConfig
{
- if (string.IsNullOrEmpty(pattern) || string.IsNullOrEmpty(domain))
- {
- return false;
- }
-
- // 简单的域名匹配,支持通配符 * (例如: *.example.com)
- if (pattern.Contains('*'))
- {
- var regexPattern = "^" + System.Text.RegularExpressions.Regex.Escape(pattern)
- .Replace("\\*", ".*") + "$";
- return System.Text.RegularExpressions.Regex.IsMatch(
- domain,
- regexPattern,
- System.Text.RegularExpressions.RegexOptions.IgnoreCase);
- }
-
- return string.Equals(pattern, domain, StringComparison.OrdinalIgnoreCase);
+ [JsonPropertyName("name")] public string? Name { get; set; }
+ [JsonPropertyName("mch_id")] public string? MchId { get; set; }
+ [JsonPropertyName("order_prefix")] public string? OrderPrefix { get; set; }
+ [JsonPropertyName("api_key")] public string? ApiKey { get; set; }
+ [JsonPropertyName("is_enabled")] public string? IsEnabled { get; set; }
+ [JsonPropertyName("pay_version")] public string? PayVersion { get; set; }
+ [JsonPropertyName("api_v3_key")] public string? ApiV3Key { get; set; }
+ [JsonPropertyName("cert_serial_no")] public string? CertSerialNo { get; set; }
+ [JsonPropertyName("private_key_path")] public string? PrivateKeyPath { get; set; }
+ [JsonPropertyName("wechat_public_key_id")] public string? WechatPublicKeyId { get; set; }
+ [JsonPropertyName("wechat_public_key_path")] public string? WechatPublicKeyPath { get; set; }
+ [JsonPropertyName("notify_url")] public string? NotifyUrl { get; set; }
+ }
+ private class DbWeixinPayConfig
+ {
+ [JsonPropertyName("appid")] public string? AppId { get; set; }
+ [JsonPropertyName("mch_id")] public string? MchId { get; set; }
+ [JsonPropertyName("keys")] public string? Keys { get; set; }
+ }
+ private class DbMiniprogramSetting { [JsonPropertyName("miniprograms")] public List? Miniprograms { get; set; } }
+ private class DbMiniprogramConfig
+ {
+ [JsonPropertyName("name")] public string? Name { get; set; }
+ [JsonPropertyName("appid")] public string? AppId { get; set; }
+ [JsonPropertyName("appsecret")] public string? AppSecret { get; set; }
+ [JsonPropertyName("order_prefix")] public string? OrderPrefix { get; set; }
+ [JsonPropertyName("is_default")] public int IsDefault { get; set; }
+ [JsonPropertyName("merchants")] public List? Merchants { get; set; }
}
}
diff --git a/server/HoneyBox/src/HoneyBox.Infrastructure/Modules/ServiceModule.cs b/server/HoneyBox/src/HoneyBox.Infrastructure/Modules/ServiceModule.cs
index b8bdfecf..f1718a0d 100644
--- a/server/HoneyBox/src/HoneyBox.Infrastructure/Modules/ServiceModule.cs
+++ b/server/HoneyBox/src/HoneyBox.Infrastructure/Modules/ServiceModule.cs
@@ -220,7 +220,8 @@ public class ServiceModule : Module
var dbContext = c.Resolve();
var logger = c.Resolve>();
var lotteryEngine = c.Resolve();
- return new OrderService(dbContext, logger, lotteryEngine);
+ var wechatPayService = c.Resolve();
+ return new OrderService(dbContext, logger, lotteryEngine, wechatPayService);
}).As().InstancePerLifetimeScope();
// 注册仓库服务
@@ -235,8 +236,14 @@ public class ServiceModule : Module
// ========== 支付系统服务注册 ==========
- // 注册微信支付配置服务
- builder.RegisterType().As().InstancePerLifetimeScope();
+ // 注册微信支付配置服务(从数据库读取配置)
+ builder.Register(c =>
+ {
+ var dbContext = c.Resolve();
+ var redisService = c.Resolve();
+ var logger = c.Resolve>();
+ return new WechatPayConfigService(dbContext, redisService, logger);
+ }).As().InstancePerLifetimeScope();
// 注册微信支付 V3 服务
builder.Register(c =>
@@ -258,8 +265,8 @@ public class ServiceModule : Module
var wechatService = c.Resolve();
var redisService = c.Resolve();
var settings = c.Resolve>();
- // 使用 Lazy 延迟解析 V3 服务,避免循环依赖
- var v3ServiceLazy = new Lazy(() => c.Resolve());
+ // Autofac 原生支持 Lazy,直接解析即可
+ var v3ServiceLazy = c.Resolve>();
return new WechatPayService(dbContext, httpClientFactory.CreateClient(), logger, configService, wechatService, redisService, settings, v3ServiceLazy);
}).As().InstancePerLifetimeScope();