ASP.NET Core 微信支付(四)【支付通知(未按照官方步骤) APIV3】

  • A+
所属分类:.NET技术
摘要

  支付通知API   netcore 中没有Request.InputStream   对于我来说,这个微信支付结果通知回调有两个难点。


官方文档

  支付通知API

参考资料

  netcore 中没有Request.InputStream

理论实战

  对于我来说,这个微信支付结果通知回调有两个难点。

    难点一

      一开始在想是怎么在.NET Core 下接受微信支付回调传递给我的数据,从参考资料中得到的解决方案就解决了这个难点。

    难点二

      如何验证签名。在我写代码的时候突然想到我为啥要验证签名,我直接解密微信支付回调的数据得到订单号,然后直接调用订单查询接口就可以了,这样就解决了难点二。

代码实战

  数据实体映射类  

    /// <summary>     /// 微信支付结果回调通知实体     /// </summary>     public class WxPayNotifyModel     {         /// <summary>         /// 通知的唯一ID         /// </summary>         public string id { set; get; }          /// <summary>         /// 通知创建时间,格式为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秒。         /// </summary>         public string create_time { set; get; }          /// <summary>         /// 通知的类型,支付成功通知的类型为TRANSACTION.SUCCESS         /// </summary>         public string event_type { set; get; }          /// <summary>         /// 通知的资源数据类型,支付成功通知为encrypt-resource         /// </summary>         public string resource_type { set; get; }          /// <summary>         /// 通知资源数据,json格式         /// </summary>         public WxPayResourceModel resource { set; get; }          /// <summary>         /// 回调摘要         /// </summary>         public string summary { set; get; }     }      /// <summary>     /// 微信支付回调通知结果resource实体     /// </summary>     public class WxPayResourceModel     {         /// <summary>         /// 对开启结果数据进行加密的加密算法,目前只支持AEAD_AES_256_GCM         /// </summary>         public string algorithm { set; get; }          /// <summary>         /// Base64编码后的开启/停用结果数据密文         /// </summary>         public string ciphertext { set; get; }          /// <summary>         /// 附加数据         /// </summary>         public string associated_data { set; get; }          /// <summary>         /// 原始回调类型,为transaction         /// </summary>         public string original_type { set; get; }          /// <summary>         /// 加密使用的随机串         /// </summary>         public string nonce { set; get; }     }      /// <summary>     /// 微信支付回调通知结果解密实体     /// </summary>     public class WxPayResourceDecryptModel     {         /// <summary>         /// 直连商户申请的公众号或移动应用appid         /// </summary>         public string appid { set; get; }          /// <summary>         /// 商户的商户号,由微信支付生成并下发。         /// </summary>         public string mchid { set; get; }          /// <summary>         /// 商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一。特殊规则:最小字符长度为6         /// </summary>         public string out_trade_no { set; get; }          /// <summary>         /// 微信支付系统生成的订单号。         /// </summary>         public string transaction_id { set; get; }          /// <summary>         /// 交易状态,枚举值:         /// SUCCESS:支付成功         /// REFUND:转入退款         /// NOTPAY:未支付         /// CLOSED:已关闭         /// REVOKED:已撤销(付款码支付)         /// USERPAYING:用户支付中(付款码支付)         /// PAYERROR:支付失败(其他原因,如银行返回失败)         /// ACCEPT:已接收,等待扣款         /// </summary>         public string trade_state { get; set; }          /// <summary>         /// 交易状态描述         /// </summary>         public string trade_state_desc { get; set; }          /// <summary>         /// 支付者信息         /// </summary>         public WxPayerResourceDecryptModel payer { set; get; }      }      /// <summary>     /// 支付用户信息实体     /// </summary>     public class WxPayerResourceDecryptModel     {         /// <summary>         /// 用户在直连商户appid下的唯一标识。         /// </summary>         public string openid { get; set; }     }

  返回给微信支付回调结果的实体类

    public class WxPayCallbackViewModel     {         /// <summary>         /// 返回状态码,错误码,SUCCESS为清算机构接收成功,其他错误码为失败。         /// </summary>         public string code { set; get; } = "SUCCESS";          /// <summary>         /// 返回信息,如非空,为错误原因。         /// </summary>         public string message { set; get; } = string.Empty;     }

  使用方法

        public async Task<WxPayCallbackViewModel> WxPayCallback()         {             var buffer = new MemoryStream();             Request.Body.CopyTo(buffer);             var str = Encoding.UTF8.GetString(buffer.GetBuffer());              var wxPayNotifyModel = str.ToObject<WxPayNotifyModel>();             var resource = wxPayNotifyModel?.resource ?? new WxPayResourceModel();             var decryptStr = AesGcm.AesGcmDecrypt(resource.associated_data, resource.nonce, resource.ciphertext);             var decryptModel = decryptStr.ToObject<WxPayResourceDecryptModel>();              var viewModel = new WxPayCallbackViewModel();             if (decryptModel.IsNotNull())             {                 var url = $"https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{decryptModel.out_trade_no}?mchid={WxPayConst.mchid}";                 var client = new HttpClient(new WxPayHelper());                 var resp = await client.GetAsync(url);                 var respStr = await resp.Content.ReadAsStringAsync();                 var payModel = respStr.ToObject<WxPayStatusRespModel>();                  return viewModel;             }              viewModel.code = "FAIL";             viewModel.message = "数据解密失败";             return new WxPayCallbackViewModel();         }