using System.Text.Json; using HoneyBox.Core.Interfaces; using HoneyBox.Model.Data; using HoneyBox.Model.Entities; using HoneyBox.Model.Models.Auth; using HoneyBox.Model.Models.Payment; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace HoneyBox.Core.Services; /// /// 微信服务实现 /// public class WechatService : IWechatService { private readonly HttpClient _httpClient; private readonly ILogger _logger; private readonly WechatPaySettings _wechatPaySettings; private readonly IRedisService _redisService; private readonly HoneyBoxDbContext _dbContext; // 微信API端点 private const string WechatCodeToSessionUrl = "https://api.weixin.qq.com/sns/jscode2session"; private const string WechatGetPhoneNumberUrl = "https://api.weixin.qq.com/wxa/business/getuserphonenumber"; private const string WechatGetAccessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token"; // Redis缓存键前缀 private const string AccessTokenCacheKeyPrefix = "wechat:access_token:"; public WechatService( HttpClient httpClient, ILogger logger, IOptions wechatPaySettings, IRedisService redisService, HoneyBoxDbContext dbContext) { _httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _wechatPaySettings = wechatPaySettings?.Value ?? throw new ArgumentNullException(nameof(wechatPaySettings)); _redisService = redisService ?? throw new ArgumentNullException(nameof(redisService)); _dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext)); } /// /// 获取微信openid和unionid /// public async Task GetOpenIdAsync(string code) { _logger.LogInformation("[微信登录] 开始处理,code={Code}", code); if (string.IsNullOrWhiteSpace(code)) { _logger.LogWarning("[微信登录] code为空"); return new WechatAuthResult { Success = false, ErrorMessage = "授权code不能为空" }; } try { // 从数据库获取微信配置 var wechatConfig = await GetWechatSettingFromDbAsync(); if (wechatConfig == null) { _logger.LogError("[微信登录] 未找到小程序配置,请在后台管理系统中配置 miniprogram_setting"); return new WechatAuthResult { Success = false, ErrorMessage = "小程序配置未设置,请联系管理员" }; } var appId = wechatConfig.AppId; var appSecret = wechatConfig.AppSecret; // 记录配置信息(脱敏) var maskedAppId = appId?.Length > 8 ? $"{appId.Substring(0, 4)}****{appId.Substring(appId.Length - 4)}" : "未配置"; var maskedSecret = string.IsNullOrEmpty(appSecret) ? "未配置" : $"{appSecret.Substring(0, 4)}****"; _logger.LogInformation("[微信登录] 配置信息: AppId={AppId}, AppSecret={AppSecret}, 来源=数据库", maskedAppId, maskedSecret); var url = $"{WechatCodeToSessionUrl}?appid={appId}&secret={appSecret}&js_code={code}&grant_type=authorization_code"; _logger.LogInformation("[微信登录] 调用微信API: {Url}", WechatCodeToSessionUrl); var response = await _httpClient.GetAsync(url); var content = await response.Content.ReadAsStringAsync(); _logger.LogInformation("[微信登录] 微信API响应状态码: {StatusCode}", response.StatusCode); _logger.LogInformation("[微信登录] 微信API响应内容: {Content}", content); if (!response.IsSuccessStatusCode) { _logger.LogError("[微信登录] 微信API返回HTTP错误 {StatusCode}: {Content}", response.StatusCode, content); return new WechatAuthResult { Success = false, ErrorMessage = "微信API调用失败" }; } using var jsonDoc = JsonDocument.Parse(content); var root = jsonDoc.RootElement; // 检查是否有错误 if (root.TryGetProperty("errcode", out var errCode) && errCode.GetInt32() != 0) { var errMsg = root.TryGetProperty("errmsg", out var msg) ? msg.GetString() : "未知错误"; _logger.LogWarning("[微信登录] 微信API返回业务错误: errcode={ErrorCode}, errmsg={ErrorMessage}", errCode.GetInt32(), errMsg); return new WechatAuthResult { Success = false, ErrorMessage = $"微信授权失败: {errMsg}" }; } // 提取openid和unionid var openId = root.TryGetProperty("openid", out var openIdProp) ? openIdProp.GetString() : null; var unionId = root.TryGetProperty("unionid", out var unionIdProp) ? unionIdProp.GetString() : null; var sessionKey = root.TryGetProperty("session_key", out var sessionKeyProp) ? sessionKeyProp.GetString() : null; _logger.LogInformation("[微信登录] 解析结果: openid={OpenId}, unionid={UnionId}, session_key={SessionKey}", openId ?? "null", unionId ?? "null", string.IsNullOrEmpty(sessionKey) ? "null" : "已获取"); if (string.IsNullOrEmpty(openId)) { _logger.LogError("[微信登录] 微信API响应中缺少openid"); return new WechatAuthResult { Success = false, ErrorMessage = "微信返回数据异常" }; } _logger.LogInformation("[微信登录] 成功获取openid: {OpenId}", openId); return new WechatAuthResult { Success = true, OpenId = openId, UnionId = unionId }; } catch (HttpRequestException ex) { _logger.LogError(ex, "[微信登录] HTTP请求异常: {Message}", ex.Message); return new WechatAuthResult { Success = false, ErrorMessage = "网络连接失败" }; } catch (JsonException ex) { _logger.LogError(ex, "[微信登录] JSON解析异常: {Message}", ex.Message); return new WechatAuthResult { Success = false, ErrorMessage = "响应数据格式错误" }; } catch (Exception ex) { _logger.LogError(ex, "[微信登录] 未知异常: {Message}", ex.Message); return new WechatAuthResult { Success = false, ErrorMessage = "系统错误" }; } } /// /// 获取微信授权的手机号 /// public async Task GetMobileAsync(string code) { if (string.IsNullOrWhiteSpace(code)) { _logger.LogWarning("GetMobileAsync called with empty code"); return new WechatMobileResult { Success = false, ErrorMessage = "授权code不能为空" }; } try { // 1. 先获取 access_token var accessToken = await GetAccessTokenAsync(); if (string.IsNullOrEmpty(accessToken)) { _logger.LogError("Failed to get access_token for phone number API"); return new WechatMobileResult { Success = false, ErrorMessage = "获取access_token失败" }; } // 2. 使用 access_token 作为 URL 参数,code 放在请求体中 var url = $"{WechatGetPhoneNumberUrl}?access_token={accessToken}"; var requestBody = new { code = code }; var jsonContent = new StringContent( JsonSerializer.Serialize(requestBody), System.Text.Encoding.UTF8, "application/json"); _logger.LogInformation("Calling WeChat API to get phone number with access_token"); var response = await _httpClient.PostAsync(url, jsonContent); var content = await response.Content.ReadAsStringAsync(); if (!response.IsSuccessStatusCode) { _logger.LogError("WeChat API returned error status {StatusCode}: {Content}", response.StatusCode, content); return new WechatMobileResult { Success = false, ErrorMessage = "微信API调用失败" }; } using var jsonDoc = JsonDocument.Parse(content); var root = jsonDoc.RootElement; // 检查是否有错误 if (root.TryGetProperty("errcode", out var errCode) && errCode.GetInt32() != 0) { var errMsg = root.TryGetProperty("errmsg", out var msg) ? msg.GetString() : "未知错误"; _logger.LogWarning("WeChat API returned error: {ErrorCode} - {ErrorMessage}", errCode.GetInt32(), errMsg); return new WechatMobileResult { Success = false, ErrorMessage = $"获取手机号失败: {errMsg}" }; } // 提取手机号 string? mobile = null; if (root.TryGetProperty("phone_info", out var phoneInfo)) { mobile = phoneInfo.TryGetProperty("phoneNumber", out var phoneNumber) ? phoneNumber.GetString() : null; } if (string.IsNullOrEmpty(mobile)) { _logger.LogError("WeChat API response missing phone number"); return new WechatMobileResult { Success = false, ErrorMessage = "微信返回数据异常" }; } _logger.LogInformation("Successfully retrieved phone number from WeChat API"); return new WechatMobileResult { Success = true, Mobile = mobile }; } catch (HttpRequestException ex) { _logger.LogError(ex, "HTTP request error when calling WeChat API"); return new WechatMobileResult { Success = false, ErrorMessage = "网络连接失败" }; } catch (JsonException ex) { _logger.LogError(ex, "JSON parsing error when processing WeChat API response"); return new WechatMobileResult { Success = false, ErrorMessage = "响应数据格式错误" }; } catch (Exception ex) { _logger.LogError(ex, "Unexpected error when calling WeChat API"); return new WechatMobileResult { Success = false, ErrorMessage = "系统错误" }; } } /// /// 获取小程序接口调用凭证(access_token) /// /// 小程序AppId(可选,不传则使用数据库默认配置) /// access_token,失败返回null public async Task GetAccessTokenAsync(string? appId = null) { try { // 从数据库获取配置 var wechatConfig = await GetWechatSettingFromDbAsync(); if (wechatConfig == null) { _logger.LogError("无法获取access_token:未找到小程序配置,请在后台管理系统中配置 miniprogram_setting"); return null; } // 确定使用哪个AppId和AppSecret var targetAppId = appId ?? wechatConfig.AppId; var targetAppSecret = await GetAppSecretByAppIdAsync(targetAppId); if (string.IsNullOrEmpty(targetAppId) || string.IsNullOrEmpty(targetAppSecret)) { _logger.LogError("无法获取access_token:AppId或AppSecret为空"); return null; } // 尝试从Redis缓存获取 var cacheKey = $"{AccessTokenCacheKeyPrefix}{targetAppId}"; var cachedToken = await _redisService.GetStringAsync(cacheKey); if (!string.IsNullOrEmpty(cachedToken)) { _logger.LogDebug("从缓存获取access_token: AppId={AppId}", targetAppId); return cachedToken; } // 调用微信API获取新的access_token var url = $"{WechatGetAccessTokenUrl}?grant_type=client_credential&appid={targetAppId}&secret={targetAppSecret}"; _logger.LogInformation("调用微信API获取access_token: AppId={AppId}", targetAppId); var response = await _httpClient.GetAsync(url); var content = await response.Content.ReadAsStringAsync(); if (!response.IsSuccessStatusCode) { _logger.LogError("微信API返回错误状态 {StatusCode}: {Content}", response.StatusCode, content); return null; } using var jsonDoc = JsonDocument.Parse(content); var root = jsonDoc.RootElement; // 检查是否有错误 if (root.TryGetProperty("errcode", out var errCode) && errCode.GetInt32() != 0) { var errMsg = root.TryGetProperty("errmsg", out var msg) ? msg.GetString() : "未知错误"; _logger.LogWarning("微信API返回错误: {ErrorCode} - {ErrorMessage}", errCode.GetInt32(), errMsg); return null; } // 提取access_token和过期时间 var accessToken = root.TryGetProperty("access_token", out var tokenProp) ? tokenProp.GetString() : null; var expiresIn = root.TryGetProperty("expires_in", out var expiresProp) ? expiresProp.GetInt32() : 7200; if (string.IsNullOrEmpty(accessToken)) { _logger.LogError("微信API响应中缺少access_token"); return null; } // 缓存access_token(提前5分钟过期,避免边界问题) var cacheExpiry = TimeSpan.FromSeconds(Math.Max(expiresIn - 300, 60)); await _redisService.SetStringAsync(cacheKey, accessToken, cacheExpiry); _logger.LogInformation("成功获取access_token: AppId={AppId}, ExpiresIn={ExpiresIn}s", targetAppId, expiresIn); return accessToken; } catch (HttpRequestException ex) { _logger.LogError(ex, "获取access_token时HTTP请求错误"); return null; } catch (JsonException ex) { _logger.LogError(ex, "获取access_token时JSON解析错误"); return null; } catch (Exception ex) { _logger.LogError(ex, "获取access_token时发生未知错误"); return null; } } /// /// 根据AppId获取对应的AppSecret(异步版本,从数据库读取) /// private async Task GetAppSecretByAppIdAsync(string appId) { // 从数据库获取配置 var wechatConfig = await GetWechatSettingFromDbAsync(); if (wechatConfig != null && wechatConfig.AppId == appId) { return wechatConfig.AppSecret; } // 从小程序配置列表中查找 var miniprogram = _wechatPaySettings.Miniprograms.FirstOrDefault(m => m.AppId == appId); if (miniprogram != null) { return miniprogram.AppSecret; } // 如果都没找到,返回数据库默认配置的AppSecret _logger.LogWarning("未找到AppId {AppId} 的配置,使用数据库默认配置", appId); return wechatConfig?.AppSecret ?? string.Empty; } /// /// 创建支付订单(原生微信支付) /// public async Task CreatePayOrderAsync(CreatePayRequest request) { try { _logger.LogInformation("[创建支付订单] 开始处理: UserId={UserId}, Price={Price}, Title={Title}, Attach={Attach}", request.UserId, request.Price, request.Title, request.Attach); // 如果金额为0,直接返回成功(免费订单) if (request.Price <= 0) { var freeOrderNo = GenerateOrderNo(request.Prefix, "MON", "YD", "MP0"); _logger.LogInformation("[创建支付订单] 免费订单,直接返回成功: OrderNo={OrderNo}", freeOrderNo); return new CreatePayResult { Status = 1, OrderNo = freeOrderNo, Res = null }; } // 获取商户配置(优先从数据库读取) var merchantConfig = await GetMerchantConfigAsync(); if (merchantConfig == null) { _logger.LogError("[创建支付订单] 未找到商户配置"); return new CreatePayResult { Status = 0, Message = "支付配置错误", OrderNo = string.Empty }; } // 生成订单号:前缀 + 商户前缀 + 小程序前缀 + 支付类型 + 时间戳 + 随机数 var orderNo = GenerateOrderNo(request.Prefix, merchantConfig.OrderPrefix, "YD", "MP0"); // 截取标题(最多30个字符) var title = request.Title.Length > 30 ? request.Title.Substring(0, 30) : request.Title; // 生成随机字符串 var nonceStr = GenerateNonceStr(); var callbackNonceStr = GenerateNonceStr(); // 生成回调通知URL var notifyUrl = GenerateNotifyUrl(request.Attach, request.UserId, orderNo, callbackNonceStr); // 获取客户端IP var clientIp = "127.0.0.1"; // 实际应从请求中获取 // 构建统一下单参数 var unifiedOrderParams = new SortedDictionary { { "appid", merchantConfig.AppId }, { "mch_id", merchantConfig.MchId }, { "nonce_str", nonceStr }, { "body", title }, { "attach", request.Attach }, { "out_trade_no", orderNo }, { "notify_url", notifyUrl }, { "total_fee", ((int)(request.Price * 100)).ToString() }, // 转换为分 { "spbill_create_ip", clientIp }, { "trade_type", "JSAPI" }, { "openid", request.OpenId } }; // 生成签名 var sign = MakeSign(unifiedOrderParams, merchantConfig.Key); unifiedOrderParams.Add("sign", sign); // 转换为XML var xmlData = DictToXml(unifiedOrderParams); _logger.LogInformation("[创建支付订单] 调用微信统一下单API: OrderNo={OrderNo}", orderNo); // 调用微信统一下单API var content = new StringContent(xmlData, System.Text.Encoding.UTF8, "application/xml"); var response = await _httpClient.PostAsync(_wechatPaySettings.UnifiedOrderUrl, content); var responseContent = await response.Content.ReadAsStringAsync(); _logger.LogInformation("[创建支付订单] 微信统一下单响应: {Response}", responseContent); // 解析响应 var result = XmlToDict(responseContent); if (result.TryGetValue("return_code", out var returnCode) && returnCode == "SUCCESS" && result.TryGetValue("result_code", out var resultCode) && resultCode == "SUCCESS") { // 获取 prepay_id if (!result.TryGetValue("prepay_id", out var prepayId)) { _logger.LogError("[创建支付订单] 微信返回数据缺少 prepay_id"); return new CreatePayResult { Status = 0, Message = "微信返回数据异常", OrderNo = string.Empty }; } // 保存订单通知记录 var orderNotify = new OrderNotify { OrderNo = orderNo, NotifyUrl = notifyUrl, NonceStr = callbackNonceStr, PayTime = DateTime.UtcNow, PayAmount = request.Price, Status = 0, // 待支付 RetryCount = 0, Attach = request.Attach, OpenId = request.OpenId, Extend = JsonSerializer.Serialize(new { orderType = request.Attach, title = title }), CreatedAt = DateTime.UtcNow, UpdatedAt = DateTime.UtcNow }; _dbContext.OrderNotifies.Add(orderNotify); await _dbContext.SaveChangesAsync(); // 生成前端支付参数 var timeStamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(); var payNonceStr = GenerateNonceStr(); var payParams = new SortedDictionary { { "appId", merchantConfig.AppId }, { "timeStamp", timeStamp }, { "nonceStr", payNonceStr }, { "package", $"prepay_id={prepayId}" }, { "signType", "MD5" } }; var paySign = MakeSign(payParams, merchantConfig.Key); _logger.LogInformation("[创建支付订单] 订单创建成功: OrderNo={OrderNo}, PrepayId={PrepayId}", orderNo, prepayId); return new CreatePayResult { Status = 1, OrderNo = orderNo, Res = new NativePayParams { AppId = merchantConfig.AppId, TimeStamp = timeStamp, NonceStr = payNonceStr, Package = $"prepay_id={prepayId}", SignType = "MD5", PaySign = paySign } }; } else { // 解析错误信息 var errorMsg = "微信支付接口返回异常"; if (result.TryGetValue("return_msg", out var returnMsg)) { errorMsg = returnMsg; } else if (result.TryGetValue("err_code_des", out var errCodeDes)) { errorMsg = errCodeDes; } _logger.LogError("[创建支付订单] 微信统一下单失败: {Error}, Response: {Response}", errorMsg, responseContent); return new CreatePayResult { Status = 0, Message = errorMsg, OrderNo = string.Empty }; } } catch (Exception ex) { _logger.LogError(ex, "[创建支付订单] 创建失败: UserId={UserId}", request.UserId); return new CreatePayResult { Status = 0, Message = "创建支付订单失败", OrderNo = string.Empty }; } } /// /// 从数据库获取微信小程序配置 /// 仅从 miniprogram_setting 读取,无配置则返回 null /// private async Task GetWechatSettingFromDbAsync() { try { // 从 miniprogram_setting 读取小程序配置 var miniprogramConfig = await _dbContext.Configs .Where(c => c.ConfigKey == "miniprogram_setting") .Select(c => c.ConfigValue) .FirstOrDefaultAsync(); if (string.IsNullOrEmpty(miniprogramConfig)) { _logger.LogWarning("[微信配置] 数据库中未找到 miniprogram_setting 配置"); return null; } var config = JsonSerializer.Deserialize(miniprogramConfig); if (!config.TryGetProperty("miniprograms", out var miniprograms) || miniprograms.ValueKind != JsonValueKind.Array) { _logger.LogWarning("[微信配置] miniprogram_setting 配置格式错误,缺少 miniprograms 数组"); return null; } // 查找默认小程序配置 (is_default = 1) foreach (var mp in miniprograms.EnumerateArray()) { var isDefault = mp.TryGetProperty("is_default", out var isDefaultProp) && (isDefaultProp.ValueKind == JsonValueKind.Number ? isDefaultProp.GetInt32() == 1 : isDefaultProp.GetString() == "1"); if (isDefault) { var appId = mp.TryGetProperty("appid", out var appIdProp) ? appIdProp.GetString() : null; var appSecret = mp.TryGetProperty("appsecret", out var appSecretProp) ? appSecretProp.GetString() : null; if (!string.IsNullOrEmpty(appId) && !string.IsNullOrEmpty(appSecret)) { _logger.LogDebug("[微信配置] 从 miniprogram_setting 读取默认小程序配置: AppId={AppId}", appId.Length > 8 ? $"{appId.Substring(0, 4)}****{appId.Substring(appId.Length - 4)}" : appId); return new WechatSettings { AppId = appId, AppSecret = appSecret }; } } } // 如果没有默认配置,使用第一个小程序配置 var firstMp = miniprograms.EnumerateArray().FirstOrDefault(); if (firstMp.ValueKind == JsonValueKind.Object) { var appId = firstMp.TryGetProperty("appid", out var appIdProp) ? appIdProp.GetString() : null; var appSecret = firstMp.TryGetProperty("appsecret", out var appSecretProp) ? appSecretProp.GetString() : null; if (!string.IsNullOrEmpty(appId) && !string.IsNullOrEmpty(appSecret)) { _logger.LogDebug("[微信配置] 从 miniprogram_setting 读取第一个小程序配置: AppId={AppId}", appId.Length > 8 ? $"{appId.Substring(0, 4)}****{appId.Substring(appId.Length - 4)}" : appId); return new WechatSettings { AppId = appId, AppSecret = appSecret }; } } _logger.LogWarning("[微信配置] miniprogram_setting 中未找到有效的小程序配置"); return null; } catch (Exception ex) { _logger.LogError(ex, "[微信配置] 从数据库读取配置失败"); return null; } } /// /// 获取商户配置(从数据库读取) /// private async Task GetMerchantConfigAsync() { try { // 从数据库读取 weixinpay 配置 var weixinpayConfig = await _dbContext.Configs .Where(c => c.ConfigKey == "weixinpay") .Select(c => c.ConfigValue) .FirstOrDefaultAsync(); if (string.IsNullOrEmpty(weixinpayConfig)) { _logger.LogError("[微信支付] 数据库中未找到 weixinpay 配置"); return null; } var config = JsonSerializer.Deserialize(weixinpayConfig); var mchId = config.TryGetProperty("mch_id", out var mchIdProp) ? mchIdProp.GetString() : null; var appId = config.TryGetProperty("appid", out var appIdProp) ? appIdProp.GetString() : null; var key = config.TryGetProperty("keys", out var keysProp) ? keysProp.GetString() : null; if (string.IsNullOrEmpty(mchId) || string.IsNullOrEmpty(key)) { _logger.LogError("[微信支付] weixinpay 配置不完整,缺少 mch_id 或 keys"); return null; } // 如果 weixinpay 中没有 appid,从 miniprogram_setting 获取 if (string.IsNullOrEmpty(appId)) { var wechatConfig = await GetWechatSettingFromDbAsync(); appId = wechatConfig?.AppId; } if (string.IsNullOrEmpty(appId)) { _logger.LogError("[微信支付] 未找到有效的 AppId 配置"); return null; } _logger.LogInformation("[微信支付] 从数据库读取配置: MchId={MchId}, AppId={AppId}", mchId, appId); return new WechatPayMerchantConfig { Name = "数据库配置", MchId = mchId, AppId = appId, Key = key, OrderPrefix = "MYH", Weight = 1 }; } catch (Exception ex) { _logger.LogError(ex, "[微信支付] 从数据库读取配置失败"); return null; } } /// /// 生成随机字符串 /// private static string GenerateNonceStr(int length = 32) { const string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; var random = new Random(); return new string(Enumerable.Repeat(chars, length) .Select(s => s[random.Next(s.Length)]).ToArray()); } /// /// 生成回调通知URL /// private string GenerateNotifyUrl(string orderType, int userId, string orderNo, string nonceStr) { var baseUrl = _wechatPaySettings.NotifyBaseUrl.TrimEnd('/'); return $"{baseUrl}/api/pay/notify?payment_type=wxpay&order_type={orderType}&user_id={userId}&order_no={orderNo}&nonce_str={nonceStr}"; } /// /// 生成签名(MD5) /// private static string MakeSign(SortedDictionary parameters, string key) { var sb = new System.Text.StringBuilder(); foreach (var kvp in parameters) { if (!string.IsNullOrEmpty(kvp.Value) && kvp.Key != "sign") { sb.Append($"{kvp.Key}={kvp.Value}&"); } } sb.Append($"key={key}"); using var md5 = System.Security.Cryptography.MD5.Create(); var inputBytes = System.Text.Encoding.UTF8.GetBytes(sb.ToString()); var hashBytes = md5.ComputeHash(inputBytes); return BitConverter.ToString(hashBytes).Replace("-", "").ToUpper(); } /// /// 字典转XML /// private static string DictToXml(SortedDictionary dict) { var sb = new System.Text.StringBuilder(); sb.Append(""); foreach (var kvp in dict) { sb.Append($"<{kvp.Key}>"); } sb.Append(""); return sb.ToString(); } /// /// XML转字典 /// private static Dictionary XmlToDict(string xml) { var dict = new Dictionary(); try { var doc = System.Xml.Linq.XDocument.Parse(xml); if (doc.Root != null) { foreach (var element in doc.Root.Elements()) { dict[element.Name.LocalName] = element.Value; } } } catch { // 解析失败返回空字典 } return dict; } /// /// 生成订单号 /// 格式:前缀(3位) + 商户前缀(3位) + 项目前缀(2位) + 支付类型(3位) + 时间戳 + 随机数 /// private string GenerateOrderNo(string prefix, string merchantPrefix, string projectPrefix, string payType) { var timestamp = DateTime.UtcNow.ToString("yyyyMMddHHmmss"); var random = new Random().Next(1000, 9999); return $"{prefix}{merchantPrefix}{projectPrefix}{payType}{timestamp}{random}"; } }