前言
最近公司要求支持银联支付,首先就会去参考官方api文档,银联支付官方文档,看完后发现是.net版本的示例文档,版无.netcore版本,于是网上搜索了一下netcore版本,发现讲解的都不全或者没有netcore版本的示例,于是决定将netcore版本的对接过程记录下来
步骤
此示例未银联支付在线网关支付模式
引用github封装好的SDK处理银联支付
Nuget安装SDK
Install-Package Essensoft.AspNetCore.Payment.UnionPay -Version 2.4.3
appsettings.json 配置项
"UnionPay": {"MerId": "ab7290058192dd0","SignCert": "certs/acp_test_sign.pfx","SignCertPassword": "000000","EncryptCert": "certs/acp_test_enc.cer","MiddleCert": "certs/acp_test_middle.cer","RootCert": "certs/acp_test_root.cer","TestMode": true,"NotifyUrl": "http://www.xxx.com/api/PayNotify/UnionPayNotify"},
新增配置实体类
using Essensoft.AspNetCore.Payment.UnionPay;
public class UnionPayOptionsExtend: UnionPayOptions
{/// <summary>/// 回调地址/// </summary>public string NotifyUrl { get; set; }
}
新增支付实体类
/// <summary>/// 银联支付/// </summary>public class UnionPayModel{/// <summary>/// 商户订单号,8-32位数字字母,不能含“-”或“_”,此处默认取demo演示页面传递的参数,可以自行定制规则/// </summary>[Required][Display(Name = "orderId")]public string OrderId { get; set; }/// <summary>/// 商户发送交易时间,格式:yyyyMMddHHmmss/// </summary>[Required][Display(Name = "txnTime")]public string TxnTime { get; set; }/// <summary>/// 交易金额,单位:分/// </summary>[Required][Display(Name = "txnAmt")]public string TxnAmt { get; set; }//[Required]//[Display(Name = "currencyCode")]//public string CurrencyCode { get; set; }/// <summary> /// 订单超时时间。/// 超过此时间后,除网银交易外,其他交易银联系统会拒绝受理,提示超时。 跳转银行网银交易如果超时后交易成功,会自动退款,大约5个工作日金额返还到持卡人账户。/// 此时间建议取支付时的北京时间加15分钟。/// 超过超时时间调查询接口应答origRespCode不是A6或者00的就可以判断为失败。/// 支付超时时间, 格式:yyyyMMddHHmmss/// </summary>[Display(Name = "payTimeout")]public string PayTimeout { get; set; }/// <summary>/// 前台通知url,点击返回商户跳转/// </summary>[Display(Name = "frontUrl")]public string FrontUrl { get; set; }/ <summary>/ 异步通知地址/ </summary>//[Required]//[Display(Name = "backUrl")]//public string BackUrl { get; set; }/// <summary>/// 保留域/// </summary>[JsonProperty("reserved")]public string Reserved { get; set; }}/// 查询实体public class UnionPayQueryModel{/// <summary>/// 订单号/// </summary>[Required][Display(Name = "orderId")]public string OrderId { get; set; }/// <summary>/// 订单交易时间 格式:yyyyMMddHHmmss/// </summary>public string TxnTime { get; set; }}
新增UnionPaymentService
using Essensoft.AspNetCore.Payment.UnionPay;
using Essensoft.AspNetCore.Payment.UnionPay.Request;
using Essensoft.AspNetCore.Payment.UnionPay.Response;
using Sup.Essensoft.Service.Options;
using Sup.Essensoft.Service.UnionPay.Model;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
public class UnionPaymentService: IUnionPaymentService
{private readonly IUnionPayClient _client;public IOptions<UnionPayOptionsExtend> _optionsAccessor { get; set; }private readonly ILogger _logger;private readonly ITracer _tracer;public UnionPaymentService(IOptions<UnionPayOptionsExtend> optionsAccessor,ILogger<UnionPaymentService> logger,IUnionPayClient client,ITracer tracer){_optionsAccessor = optionsAccessor;_logger = logger;_client = client;_tracer = tracer;}/// <summary>/// 银联网关支付/// </summary>/// <param name="model"></param>/// <returns></returns>public async Task<UnionPayNullResponse> UnionPayGatewayPay(UnionPayModel model){IScope spanScope = null;try{spanScope = _tracer.BuildSpan("UnionPayGatewayPay").WithTag(Tags.Component, nameof(UnionPaymentService)).WithBusinessId(model.OrderId).StartActive();_logger.LogInformation($"银联支付入参:{model.ToJson()}");var request = new UnionPayGatewayPayFrontConsumeRequest(){TxnType = "01",//交易类型TxnSubType = "01",//交易子类BizType = "000201",//业务类型ChannelType = "07",//渠道类型CurrencyCode = "156",//交易币种OrderId = model.OrderId,TxnAmt = model.TxnAmt,TxnTime = model.TxnTime,PayTimeOut = model.PayTimeout,FrontUrl = model.FrontUrl,BackUrl = _optionsAccessor.Value.NotifyUrl,};_logger.LogInformation($"银联入参:{request.ToJson()}");var response = await _client.PageExecuteAsync(request, _optionsAccessor.Value);_logger.LogInformation($"银联支付出参:{response.ToJson()}");return response;}catch (Exception ex){_logger.LogInformation($"银联支付异常:{ex.Message},{ex.StackTrace}");throw ex;}finally{spanScope?.Dispose();}}/// <summary>/// 银联支付查询/// </summary>/// <param name="model"></param>/// <returns></returns>public async Task<UnionPayGatewayPayQueryResponse> UnionPayQuery(UnionPayQueryModel model){IScope spanScope = null;try{spanScope = _tracer.BuildSpan("UnionPayQuery").WithTag(Tags.Component, nameof(UnionPaymentService)).WithBusinessId(model.OrderId).StartActive();var request = new UnionPayGatewayPayQueryRequest{TxnType = "00",//交易类型TxnSubType = "00",//交易子类BizType = "000201",//业务类型OrderId = model.OrderId,TxnTime = model.TxnTime,};_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();}}
}
新增IUnionPaymentService
public interface IUnionPaymentService{/// <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<UnionPayNullResponse> UnionPayGatewayPay(UnionPayModel model);/// <summary>/// 银联支付查询/// </summary>/// <param name="model"></param>/// <returns></returns>Task<UnionPayGatewayPayQueryResponse> UnionPayQuery(UnionPayQueryModel model);}
新增PayController,处理发起支付入口
private readonly IUnionPaymentService _unionPaymentService;/// <summary>
/// 银联网关支付
/// </summary>
/// <param name="viewMode"></param>
/// <returns></returns>
[HttpPost("UnionPayGatewayPay")]
[ProducesResponseType(typeof(string), 200)]
[Trace("orderId", "aid")]
public async Task<IActionResult> UnionPayGatewayPay([FromBody] UnionPayModel viewMode)
{var data = await _unionPaymentService.UnionPayGatewayPay(viewMode);if (!string.IsNullOrEmpty(data?.Body)){return Ok(ResponseResult.Execute(data?.Body));}return Ok(ResponseResult.Execute("-1", $"银联支付异常"));
}/// <summary>
/// 银联支付查询
/// </summary>
/// <param name="viewMode"></param>
/// <returns></returns>
[HttpGet("UnionPayQuery")]
[ProducesResponseType(typeof(DataResponse), 200)]
[Trace("out_trade_no", "aid")]
public async Task<IActionResult> UnionPayQuery([FromQuery] UnionPayQueryModel viewMode)
{var data = await _unionPaymentService.UnionPayQuery(viewMode);if (data.RespCode == "00" && data.OrigRespCode == "00"){return Ok(ResponseResult.Execute(data));}return Ok(ResponseResult.Execute("-1", $"银联查询交易失败:{data?.RespCode},{data?.RespMsg}"));
}
新增PayNotifyController,处理异步通知
private readonly IUnionPaymentService _unionPaymentService;/// <summary>
/// 微信支付结果通知
/// </summary>
/// <returns></returns>
[HttpPost("UnionPayNotify")]
public async Task<IActionResult> UnionPayNotify()
{var result = UnionPayNotifyResult.Failure;try{var notify = await _unionPayNotifyClient.ExecuteAsync<UnionPayGatewayPayFrontConsumeNotify>(Request, _unionPayOptionsAccessor.Value);_logger.LogInformation("银联支付回调参数: " + notify?.ToJson());if (notify == null){_logger.LogInformation($"银联支付回调通知为空");return NoContent();}_tracer.ActiveSpan.SetTag("aid", notify?.OrderId);_logger.LogInformation("银联支付回调订单号: " + notify.OrderId);if ("00" == notify.RespCode || "A6" == notify.RespCode){_logger.LogInformation($"银联支付成功:{notify.OrderId}");result = UnionPayNotifyResult.Success;}return result;}catch (Exception ex){_logger.LogInformation($"银联支付回调通知异常:{ex.ToString()}");}return NoContent();
}
PostMan测试结果
{"data": "<form id='submit' name='submit' action='https://gateway.test.95516.com/gateway/api/frontTransReq.do' method='post' style='display:none;'><input name='bizType' value='000201'/><input name='txnTime' value='20210706090137'/><input name='backUrl' value='http://m344739968.vicp.cc/api/PayNotify/UnionPayNotify'/><input name='currencyCode' value='156'/><input name='txnAmt' value='800'/><input name='txnType' value='01'/><input name='txnSubType' value='01'/><input name='channelType' value='07'/><input name='orderId' value='10221062810212809421'/><input name='frontUrl' value='http://www.baidu.com'/><input name='payTimeout' value='20210706100137'/><input name='version' value='5.1.0'/><input name='encoding' value='UTF-8'/><input name='signMethod' value='01'/><input name='accessType' value='0'/><input name='merId' value='777290058192030'/><input name='certId' value='69629715588'/><input name='signature' value='mXI/atwmc7qsErWv7ZusQma86Msl4bYle4vy/8Tr9fBYDEuljamdtzIXsR590FiMGrPaBXVK2xkIBypqc6RsbILIx9FRawbMRwAYF6GOU1aCPYOFmweOT9JgP9C31jwY5E/ooZR7w/o8rCWMuHPkxyDTmdXsQBTifvE9ac30qD5PZq0EyBB0FKX3k03j9s9190n4Q/UTwh4Xsj5uBBaflGUGF611iKvxkhF1++7WHUsrR98fXMlPbpSDq++nYiNLl6jKP/j5msxJU2mrffV2ia2o4TzuHHjoYHUhzjKvpecCoXmnkX5eqlYn6UAPBlw7u2HR9fPk4EbhLGtjNCzKow=='/><input type='submit' style='display:none;'></form><script>document.forms['submit'].submit();</script>","code": "0","message": "发起支付成功","messageType": 1
}
前端拿到返回结果,发起提交表单,将会跳转到银联支付收银台页面,完成支付后等待银联支付通知即可
总结
- 以上代码仅仅是核心源代码,仅供参考