UnionPay-银联支付-netcore(二)

前言

最近公司要求支持银联支付,首先就会去参考官方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
}

前端拿到返回结果,发起提交表单,将会跳转到银联支付收银台页面,完成支付后等待银联支付通知即可

总结

  1. 以上代码仅仅是核心源代码,仅供参考
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值