• Asp.Net Core3.0 微信小程序统一下单


    微信统一下单开发文档:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1

    微信支付小程序支付文档:https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_8_1.shtml

    简单记录一下net core3.0对接微信支付的相关代码,网上有很多微信支付的文章,但是一定要仔细看一遍微信的官方文档。

    准备工作:

    首先要开通小程序的支付能力,按要求提交审核材料,审核通过后,我们可以得到APPID、微信支付商户号mch_id、API密钥key、Appsecret,详见 https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=3_1

    之后在商户后台绑定同一主体的APPID并授权,发起授权后,商户需要自行前往对应平台确认授权申请。

    最后在商户后台设置回调地址。

    一、微信支付

    1.支付V3

    代码只是简单实现退款功能,仅供参考,请勿在生产环境中使用,否则可能造成资金风险。

    //支付接口 
     public async Task<ResponseResult<dynamic>> unifiedorder(int money)
    {
      var url = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi"; var req = new GenerateOrderModelForWxPay { appid = _appid, mchid = _mchid, description = "XXXXX支付交易单", amount = new WxPayAmountModel { total = money, currency = "CNY" }, payer = new WxPayerModel { openid = "付款人的openid" }, out_trade_no = DateTime.Now.ToString("yyyyMMddhhmmss"), notify_url = "http://api.xxxx.com/api/pay/NotifyUrl" //支付回调,自己创建 }; _log.WriteLog(JsonConvert.SerializeObject(req)); var httpHandler = new HttpHandler(_mchid, _serialNo); HttpClient client = new HttpClient(httpHandler); var bodyJson = new StringContent(JsonConvert.SerializeObject(req), Encoding.UTF8, "application/json"); //一定要这样传递参数,不然在加密签名的时候获取到的参数就是\\u0这种形式的数据了,不是传递的这样的数据了,导致加密的结果不正确 var response = await client.PostAsync(url, bodyJson); var respStr = await response.Content.ReadAsStringAsync();//读取统一下单之后的返回结果,这样读取出来的直接就是结果,或者错误原因。这里面就包含prepay_id了

            var timeStamp = DateTimeOffset.Now.ToUnixTimeSeconds();
            var nonceStr = Path.GetRandomFileName();
            string message = $"{_appid}\n{timeStamp}\n{nonceStr}\nprepay_id={JsonConvert.DeserializeObject<dynamic>(respStr).prepay_id}\n";
            string signature = httpHandler.Sign(message);
            var newObj = new
            {
            timeStamp= timeStamp.ToString(),
            nonceStr = nonceStr,
            package= "prepay_id="+JsonConvert.DeserializeObject<dynamic>(respStr).prepay_id,
            paySign = signature
            };
            return new ResponseResult<dynamic>()
            {
            Code = Constant.Success,
            Data=JsonConvert.SerializeObject(newObj),
            };

    }

    //model

    public class WxPayAmountModel

    {
      public int total { get; set; }
      public string currency { get; set; }
    }

    public class WxPayerModel
    {
      public string openid { get; set; }
    }

    /// <summary>
    /// 支付resource
    /// </summary>
    public class GenerateOrderModelForWxPay
    {
      public string appid { get; set; }
      public string mchid { get; set; }
      public string description { get; set; }
      public WxPayAmountModel amount { get; set; }
      public WxPayerModel payer { get; set; }
      public string out_trade_no { get; set; }
      public string notify_url { get; set; }
    }

    支付完成后,微信返回的结果格式如下:

    <xml>
       <return_code><![CDATA[SUCCESS]]></return_code>
       <return_msg><![CDATA[OK]]></return_msg>
       <appid><![CDATA[wx2421b1c4370ec43b]]></appid>
       <mch_id><![CDATA[10000100]]></mch_id>
       <nonce_str><![CDATA[IITRi8Iabbblz1Jc]]></nonce_str>
       <openid><![CDATA[oUpF8uMuAJO_M2pxb1Q9zNjWeS6o]]></openid>
       <sign><![CDATA[7921E432F65EB8ED0CE9755F0E86D72F]]></sign>
       <result_code><![CDATA[SUCCESS]]></result_code>
       <prepay_id><![CDATA[wx201411101639507cbf6ffd8b0779950874]]></prepay_id>
       <trade_type><![CDATA[JSAPI]]></trade_type>
    </xml>

    2.支付结果通知:

    支付完成后,微信会把相关支付结果及用户信息通过数据流的形式发送给商户,商户需要接收处理,并按文档规范返回应答。

    通知频率为15s/15s/30s/3m/10m/20m/30m/30m/30m/60m/3h/3h/3h/6h/6h - 总计 24h4m)这里通知发送可能会多台服务器进行发送,且发送时间可能会在几秒内,但微信不保证通知最终一定能成功。

    支付成功后,微信会将结果通知商户后台,即支付代码里的notify_url链接,该链接是通过【统一下单API】中提交的参数notify_url设置,如果链接无法访问,商户将无法接收到微信通知。

    微信调用回调地址返回数据格式:
    <xml>
      <appid><![CDATA[wx2421b1c4370ec43b]]></appid>
      <attach><![CDATA[支付测试]]></attach>
      <bank_type><![CDATA[CFT]]></bank_type>
      <fee_type><![CDATA[CNY]]></fee_type>
      <is_subscribe><![CDATA[Y]]></is_subscribe>
      <mch_id><![CDATA[10000100]]></mch_id>
      <nonce_str><![CDATA[5d2b6c2a8db53831f7eda20af46e531c]]></nonce_str>
      <openid><![CDATA[oUpF8uMEb4qRXf22hE3X68TekukE]]></openid>
      <out_trade_no><![CDATA[1409811653]]></out_trade_no>
      <result_code><![CDATA[SUCCESS]]></result_code>
      <return_code><![CDATA[SUCCESS]]></return_code>
      <sign><![CDATA[B552ED6B279343CB493C5DD0D78AB241]]></sign>
      <time_end><![CDATA[20140903131540]]></time_end>
      <total_fee>1</total_fee>
      <coupon_fee><![CDATA[10]]></coupon_fee>
      <coupon_count><![CDATA[1]]></coupon_count>
      <coupon_type><![CDATA[CASH]]></coupon_type>
      <coupon_id><![CDATA[10000]]></coupon_id>
      <trade_type><![CDATA[JSAPI]]></trade_type>
      <transaction_id><![CDATA[1004400740201409030005092168]]></transaction_id>
    </xml>

    获取到微信的通知后,商户处理业务逻辑后要同步返回给微信结果,SUCCESS表示商户接收通知成功并校验成功。

            public dynamic NotifyUrl(NotifyDto ret)
            {
                WxPayAPI.WxPayData res = new WxPayAPI.WxPayData();
                res.SetValue("return_code", "FAIL");
                res.SetValue("return_msg", "订单查询失败");
    
                try
                {
                    if (ret.Event_type == "TRANSACTION.SUCCESS")//支付成功
                    {
                        //解密数据报文
                        var dataJson = AesGcmHelper.AesGcmDecryptFromBase64(_key, ret.Resource.Nonce, ret.Resource.Ciphertext, ret.Resource.Associated_data);
                        //转换对象接受
                        var data = JsonConvert.DeserializeObject<PayCipherText>(dataJson);
                        //处理自己的业务逻辑
                         TODO...
    
                        res.SetValue("return_code", "SUCCESS");
                        res.SetValue("return_msg", "OK");
                        return Content(res.ToXml());
                    }
                    else
                    {
                        _log.WriteLog("NotifyFaile:" + JsonConvert.SerializeObject(ret));
    
                    }
                    return Content(res.ToXml());
                }
                catch (Exception ex)
                {
                    _log.WriteLog(ex.ToString());
                    return Content(res.ToXml());
                }
            }

    /// 支付结果回调接收参数
    public class NotifyDto
    {
    /// 通知ID通知的唯一ID
    /// 示例值:EV-2018022511223320873
    public string Id { get; set; }
    /// 通知创建时间 通知创建的时间,遵循rfc3339标准格式,格式为YYYY-MM-DDTHH:mm:ss+TIMEZONE,YYYY-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss.表示时分秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。例如:2015-05-20T13:29:35+08:00表示北京时间2015年05月20日13点29分35秒。
    /// 示例值:2015-05-20T13:29:35+08:00
    public string Create_time { get; set; }
    /// 通知类型 通知的类型,支付成功通知的类型为TRANSACTION.SUCCESS
    /// 示例值:TRANSACTION.SUCCESS
    public string Event_type { get; set; }
    /// 通知数据类型 通知的资源数据类型,支付成功通知为encrypt-resource
    /// 示例值:encrypt-resource
    public string Resource_type { get; set; }
    /// 通知数据 通知资源数据
    /// json格式,见示例
    public Resource Resource { get; set; }
    /// 回调摘要
    /// 示例值:支付成功

    public string Summary { get; set; }
    }

    //回报文model

    public class PayCipherText
    {
    public string out_trade_no { get; set; }
    public string transaction_id { get; set; }
    public string trade_type { get; set; }
    public string trade_state { get; set; }
    public string trade_state_desc { get; set; }
    public string bank_type { get; set; }
    public string success_time { get; set; }
    public WxPayAmountModel amount { get; set; }
    }

    这里用到证书和回调报文解密,参考https://wechatpay-api.gitbook.io/wechatpay-api-v3/qian-ming-zhi-nan-1/zheng-shu-he-hui-tiao-bao-wen-jie-mi

  • 相关阅读:
    hdoj 2586 How far away?(最近公共祖先)
    poj 1330 A-Nearest Common Ancestors
    心形图
    B1928 日期差值
    B1022 D进制的A+B
    B1009 说反话
    hihocoder 1498 签到
    51Nod 1082 与7无关的数
    51Nod 1015 水仙花数
    51Nod 1283 最小周长
  • 原文地址:https://www.cnblogs.com/nowar/p/16083173.html
Copyright © 2020-2023  润新知