前言
最近公司要求支持PC微信扫码,首先就会去取官方api文档,微信支付官方文档,官方文档由于缺少完整代码对接示例,
步骤
此示例是PC微信扫码支付
引用github封装好的SDK处理微信支付
Nuget安装SDK
Install-Package Essensoft.AspNetCore.Payment.WeChatPay -Version 2.4.3
appsettings.json 配置项
"WeChatPay": {
"AppId": "wxxxxxxxxxxxxxxxxxx",
"MchId": "666666666",
"Key": "xxxxxxxxxxxxxxxxxxxxxxxx",
"NotifyUrl": "https://www.xxx.com/api/PayNotify/WechatPayNotify"
},
新增配置实体类
using Essensoft.AspNetCore.Payment.WeChatPay;
public class WeChatPayOptionsExtend: WeChatPayOptions
{
/// <summary>
/// 回调地址
/// </summary>
public string NotifyUrl { get; set; }
}
新增支付实体类
/// <summary>
/// 微信Native支付Model
/// </summary>
public class WeChatPayNativePayModel
{
/// <summary>
/// 商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|* 且在同一个商户号下唯一
/// </summary>
[JsonProperty("out_trade_no")]
public string OutTradeNo { get; set; }
/// <summary>
/// 商品简单描述
/// </summary>
[JsonProperty("body")]
public string Body { get; set; }
/// <summary>
/// 订单总金额,单位为分
/// </summary>
[JsonProperty("total_fee")]
public int TotalFee { get; set; }
/// <summary>
/// 用户的客户端IP,支持IPV4和IPV6两种格式的IP地址
/// </summary>
[JsonProperty("spbill_create_ip")]
public string SpbillCreateIp { get; set; }
/// <summary>
/// 附加数据(在查询API和支付通知中原样返回,可作为自定义参数使用)
/// </summary>
[JsonProperty("attach")]
public string Attach { get; set; }
}
/// <summary>
/// 微信支付查询model
/// </summary>
public class WeChatPayOrderQueryModel
{
/// <summary>
/// 微信的订单号(与商户订单号二选一,建议优先使用)
/// </summary>
[JsonProperty("transaction_id")]
public string TransactionId { get; set; }
/// <summary>
/// 商户订单号(与微信订单号二选一)
/// </summary>
[JsonProperty("out_trade_no")]
public string OutTradeNo { get; set; }
}
新增UnionPaymentService
public class WechatPaymentService: IWechatPaymentService
{
private readonly IWeChatPayClient _client ;
public IOptions<WeChatPayOptionsExtend> OptionsAccessor { get; set; }
private readonly ILogger _logger;
private readonly ITracer _tracer;
public WechatPaymentService(IOptions<WeChatPayOptionsExtend> optionsAccessor, ILogger<WechatPaymentService> logger, IWeChatPayClient client, ITracer tracer)
{
OptionsAccessor = optionsAccessor;
_logger = logger;
_client = client;
_tracer = tracer;
}
/// <summary>
/// 微信Native支付
/// 微信后台系统返回链接参数code_url,商户后台系统将code_url值生成二维码图片,用户使用微信客户端扫码后发起支付。注意:code_url有效期为2小时,过期后扫码不能再发起支付
/// https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_5&index=3
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public async Task<WeChatPayUnifiedOrderResponse> NativePay(WeChatPayNativePayModel model)
{
IScope spanScope = null;
try
{
spanScope = _tracer.BuildSpan("NativePay")
.WithTag(Tags.Component, nameof(WechatPaymentService))
.WithBusinessId(model.OutTradeNo)
.StartActive();
_logger.LogInformation($"微信Native支付入参:{model.ToJson()}");
var request = new WeChatPayUnifiedOrderRequest()
{
Body = model.Body,
OutTradeNo = model.OutTradeNo,
TotalFee = model.TotalFee,
SpBillCreateIp = model.SpbillCreateIp,
NotifyUrl = OptionsAccessor.Value.NotifyUrl,
Attach = model.Attach,
TradeType = "NATIVE",
TimeStart = DateTime.Now.ToString("yyyyMMddHHmmss"),
TimeExpire = DateTime.Now.AddMinutes(15).ToString("yyyyMMddHHmmss")
};
_logger.LogInformation($"微信Native支付入参:{request.ToJson()}");
var response = await _client.ExecuteAsync(request, OptionsAccessor.Value);
_logger.LogInformation($"微信Native支付出参:{response.ToJson()}");
return response;
}
catch (Exception ex)
{
_logger.LogInformation($"微信Native支付异常:{ex.Message},{ex.StackTrace}");
throw ex;
}
finally
{
spanScope?.Dispose();
}
}
/// <summary>
/// 微信支付查询
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public async Task<WeChatPayOrderQueryResponse> Query(WeChatPayOrderQueryModel model)
{
IScope spanScope = null;
try
{
spanScope = _tracer.BuildSpan("NativePay")
.WithTag(Tags.Component, nameof(WechatPaymentService))
.WithBusinessId(model.OutTradeNo)
.StartActive();
var request = new WeChatPayOrderQueryRequest
{
TransactionId = model.TransactionId,
OutTradeNo = model.OutTradeNo
};
_logger.LogInformation($"微信查询入参:{request.ToJson()}");
var response = await _client.ExecuteAsync(request, OptionsAccessor.Value);
_logger.LogInformation($"微信查询出参:{response.ToJson()}");
return response;
}
catch (Exception ex)
{
_logger.LogInformation($"微信支付查询异常:{ex.Message},{ex.StackTrace}");
throw ex;
}
finally
{
spanScope?.Dispose();
}
}
}
新增IWechatPaymentService
public interface IWechatPaymentService
{
IOptions<WeChatPayOptionsExtend> OptionsAccessor { get; set; }
/// <summary>
/// 微信Native支付
/// 微信后台系统返回链接参数code_url,商户后台系统将code_url值生成二维码图片,用户使用微信客户端扫码后发起支付。注意:code_url有效期为2小时,过期后扫码不能再发起支付
/// https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_5&index=3
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
Task<WeChatPayUnifiedOrderResponse> NativePay(WeChatPayNativePayModel model);
/// <summary>
/// 微信支付查询
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
Task<WeChatPayOrderQueryResponse> Query(WeChatPayOrderQueryModel model);
}
}
新增PayController,处理发起支付入口
private readonly IWechatPaymentService _wechatPaymentService;
/// <summary>
/// 微信Native支付
/// </summary>
/// <param name="viewMode"></param>
/// <returns></returns>
[HttpPost("WeChatNativePay")]
public async Task<IActionResult> WeChatNativePay([FromBody] WeChatPayNativePayModel viewMode)
{
var data = await _wechatPaymentService.NativePay(viewMode);
if (data.ReturnCode == "SUCCESS" && data.ResultCode == "SUCCESS")
{
PayLink payLink = new PayLink(data.CodeUrl);
return Ok(ResponseResult.Execute(payLink.ToString()));
}
return Ok(ResponseResult.Execute("-1", $"{data.ErrCode}{data.ErrCodeDes}{data.ReturnMsg}"));
}
/// <summary>
/// 微信支付查询
/// </summary>
/// <param name="viewMode"></param>
/// <returns></returns>
[HttpGet("WeChatQuery")]
public async Task<IActionResult> WeChatQuery([FromQuery] WeChatPayOrderQueryModel viewMode)
{
var data = await _wechatPaymentService.Query(viewMode);
if (data.ReturnCode == "SUCCESS" && data.ResultCode == "SUCCESS")
{
WeChatContext context = new WeChatContext(data.ResponseBody);
//解析返回的订单状态
WeChatPayOrderQueryResponse response = new WeChatPayXmlParser<WeChatPayOrderQueryResponse>().Parse(context.Context);
return Ok(ResponseResult.Execute(response));
}
return Ok(ResponseResult.Execute("-1", $"{data.ErrCode}{data.ErrCodeDes}"));
}
新增PayNotifyController,处理异步通知
private readonly IWechatPaymentService _wechatPaymentService;
/// <summary>
/// 微信支付结果通知
/// </summary>
/// <returns></returns>
[HttpPost("WechatPayNotify")]
public async Task<IActionResult> WechatPayNotify()
{
IScope spanScope = null;
var result = WeChatPayNotifyResult.Failure;
try
{
//解析返回参数
Request.EnableRewind();
var weChatModel = (await GetOrderInfoWechat(Request));
_logger.LogInformation($"回调参数:{weChatModel.ToJson()}");
_tracer.ActiveSpan.SetTag("aid", weChatModel?.OutTradeNo);
Request.Body.Position = 0;
var notify = await _wclient.ExecuteAsync<WeChatPayUnifiedOrderNotify>(Request, _woptionsAccessor.Value);
_logger.LogInformation("微信回调参数: " + notify?.ToJson());
if (notify == null)
{
_logger.LogInformation($"微信回调通知为空");
return NoContent();
}
if (notify.ReturnCode == "SUCCESS")
{
if (notify.ResultCode == "SUCCESS")
{
_logger.LogInformation($"微信支付成功:{weChatModel.OutTradeNo}");
result = WeChatPayNotifyResult.Success;
}
}
return result;
}
catch (Exception ex)
{
_logger.LogInformation($"微信回调通知异常:{ex.ToString()}");
return NoContent();
}
}
/// <summary>
/// 微信回调获取订单信息
/// </summary>
private async Task<WeChatPayUnifiedOrderNotify> GetOrderInfoWechat(HttpRequest request)
{
var body = await new StreamReader(request.Body, Encoding.UTF8).ReadToEndAsync();
var parser = new WeChatPayXmlParser<WeChatPayUnifiedOrderNotify>();
var rsp = parser.Parse(body);
return rsp;
}
总结
- 以上代码仅仅是核心源代码,仅供参考