C#\.Net实现微信小程序支付功能

前提: 要已注册微信商户号和已申请小程序支付功能。否则,请先去申请小程序微信支付功能 和 注册商家商户信息

一、配置信息

1、登录微信公众平台:mp.weixin.qq.com

2、获取到小程序的:appId,secret

3、获取到商户号和key:mchId,key

二、实现思路

1、微信用户通过 wx.login 获取到 code 去后端请求用户所在小程序对应的 openId

2、小程序通过用户 openId支付金额 访问后端去微信下单订单生成预支付交易会话标识:prepay_id ,并在后端组装一个 微信支付定义的数据对象 返回给小程序

3、小程序通过后端返回的 微信数据对象 去使用 wx.requestPayment 支付接口实现输入密码支付功能

小程序下单支付官方文档 :小程序下单 - 小程序支付 | 微信支付商户文档中心 (qq.com)

三、代码实现

配置信息

c 复制代码
 //所需值
static string _appid = "wx*******b";//小程序ID
static string _secret = "9ec*******dada";//小程序App/Secret
static string _mch_id = "1*******4";//商户号
static string _key = "yc*******11";//微信支付的Key/Secret
//获取token地址
static string getOpenId = "https://api.weixin.qq.com/sns/jscode2session?
                          appid={0}&secret={1}&grant_type=authorization_code&js_code={2}";

1、后端代码

1.1、获取用户openId

csharp 复制代码
 /// <summary>
 /// 获取用户openId
 /// </summary>
 /// <param name="js_code">通过wx.login获取到的code</param>
 /// <returns></returns>
[HttpGet("GetOpenId")]
public string GetOpenId(string js_code)
{
    string url = string.Format(getOpenId, _appid, _secret ,js_code);
    WebClient wc = new WebClient();
    Encoding enc = Encoding.GetEncoding("UTF-8");
    Byte[] pageData = wc.DownloadData(url);
    return enc.GetString(pageData);
}

1.2、进行微信小程序下单获取预支付标识prepay_id 并组装微信支付数据对象返回给前端

ini 复制代码
 /// <summary>
 /// 模拟wx统一下单
 /// </summary>
 /// <param name="openid">前台获取用户标识</param>
 /// <returns></returns>
 [HttpGet]
 public string Get(string openid, decimal amount)
 {
     string notify_url = "http://www.weixin.qq.com/wxpay/pay.php";//微信支付通知地址
     string attach = "附加数据";//附加数据,自定义数据说明
     var url = "https://api.mch.weixin.qq.com/pay/unifiedorder";//微信统一下单请求地址
     string body = "JSAPI支付测试";
     int total_fee = Convert.ToInt32(amount * 100);//支付金额,需要输入的金额*100  是微信接收的金额

     #region 生成随机串
     const string key = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
     Random rnd = new Random();
     byte[] buffer = new byte[8];
     ulong bit = 31;
     ulong result = 0;
     int index = 0;
     StringBuilder _nonce_str = new StringBuilder(32);

     while (_nonce_str.Length < 32)
     {
         rnd.NextBytes(buffer);
    
         buffer[5] = buffer[6] = buffer[7] = 0x00;
         result = BitConverter.ToUInt64(buffer, 0);
    
         while (result > 0 && _nonce_str.Length < 32)
         {
             index = (int)(bit & result);
             _nonce_str.Append(key[index]);
             result = result >> 5;
         }
     }
     string nonce_str = _nonce_str.ToString();
     #endregion

     #region 生成随机订单号
     Random rd = new Random();//用于生成随机数
     string DateStr = DateTime.Now.ToString("yyyyMMddHHmmssMM");//日期
     string bookingNo = DateStr + rd.Next(10000).ToString().PadLeft(4, '0');//带日期的随机数
     #endregion

     string strk = "appid=" + _appid + "&attach="+ attach + "&body="+ body + "&mch_id=" + _mch_id + "&nonce_str=" + nonce_str + "&notify_url=" + notify_url + 
         "&openid=" + openid + "&out_trade_no=" + bookingNo + "&spbill_create_ip=61.50.221.43&total_fee=" + total_fee + "&trade_type=JSAPI&key="+ _key;

     #region 签名 数据组装
     var formData = "<xml>";
     formData += "<appid>" + _appid + "</appid>";//appid  
     formData += "<attach>" + attach + "</attach>"; //附加数据(描述)
     formData += "<body>" + body + "</body>";//商品描述
     formData += "<mch_id>" + _mch_id + "</mch_id>";//商户号  
     formData += "<nonce_str>" + nonce_str + "</nonce_str>";//随机字符串,不长于32位。  
     formData += "<notify_url>" + notify_url + "</notify_url>";//通知地址
     formData += "<openid>" + openid + "</openid>";//openid
     formData += "<out_trade_no>" + bookingNo + "</out_trade_no>";//商户订单号
     formData += "<spbill_create_ip>61.50.221.43</spbill_create_ip>";//终端IP
     formData += "<total_fee>" + total_fee + "</total_fee>";//支付金额单位为(分)
     formData += "<trade_type>JSAPI</trade_type>";//交易类型(JSAPI--公众号支付)
     formData += "<sign>" + MD5(strk).ToUpper() + "</sign>"; //签名
     formData += "</xml>";
     #endregion

     #region 发送请求数据,去微信进行下单 获取prepay_id预支付标识
     WebClient wCient = new WebClient();
     wCient.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
     byte[] responseData = wCient.UploadData(url, "POST", Encoding.UTF8.GetBytes(formData));
     //微信返回接收的数据 
     string getdata = Encoding.UTF8.GetString(responseData);
     #endregion

     //获取xml数据
     XmlDocument doc = new XmlDocument();
     doc.LoadXml(getdata);
     //xml格式转json
     string json = JsonConvert.SerializeXmlNode(doc);
     JObject jo = (JObject)JsonConvert.DeserializeObject(json);
     string prepay_id = jo["xml"]["prepay_id"]["#cdata-section"].ToString();

     //时间戳
     TimeSpan ts = DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0, 0);
     string _time = Convert.ToInt64(ts.TotalSeconds).ToString();

     //再次签名返回数据至小程序
     string strB = "appId=" + _appid + "&nonceStr=" + nonce_str + "&package=prepay_id=" + prepay_id + "&signType=MD5&timeStamp=" + _time + "&key=" + _key;

     //wx自己写的一个类
     //向小程序返回json数据
     return JsonConvert.SerializeObject(new
     {
         timeStamp = _time,
         nonceStr = nonce_str,
         package = "prepay_id=" + prepay_id,
         paySign = MD5(strB).ToUpper(),
         signType = "MD5",

     });
 }

MD5加密数据方法

csharp 复制代码
 /// <summary>
 /// MD5签名方法  
 /// </summary>  
 /// <param name="inputText">加密参数</param>  
 /// <returns></returns>  
 private static string MD5(string inputText)
 {
     MD5 md5 = new MD5CryptoServiceProvider();
     byte[] fromData = System.Text.Encoding.UTF8.GetBytes(inputText);
     byte[] targetData = md5.ComputeHash(fromData);
     string byte2String = null;

     for (int i = 0; i < targetData.Length; i++)
     {
         byte2String += targetData[i].ToString("x2");
     }

     return byte2String;
 }

2、前端代码

2.1、页面代码,一个输入金额的文本框,一个支付按钮

ini 复制代码
  <view class='add_btn'>
     <input class="weui-input" style="margin-left: 20px;margin-right:20px;" type="number" bindinput="inputvalue" placeholder="¥请输入充值金额" />
     <button style="width:100vw;margin-top:20px;" bindtap="payment" class="btn"> 支付 </button>
  </view>

2.2、方法代码

javascript 复制代码
Page({
  //获取openid
  payment: function() {
    var that = this;
    wx.login({
      success: res => {
        if (res.code) {
          //console.log('临时登录凭证code:' + res.code);
          wx.request({
            url: 'https://localhost:7033/api/WeChatPay/GetOpenId?js_code=' + res.code,
            method: 'GET',
            header: {
              'content-type': 'application/json'
            },
            success: function(openIdRes) {
              var openid = openIdRes.data.openid;
              console.info("登录成功返回的openId:" + openid);
              that.generateOrder(openid)
            },
            fail: function(error) {
              console.info(error);
            }
          })
        }
      }
    })
  },
  //生成商户订单
  generateOrder: function(e) {
    var that = this;
    wx.request({
      url: 'https://localhost:7033/api/WeChatPay',
      data: {
        openid: e, //用户openId
        amount: 0.01  //支付金额
      },
      method: 'GET',
      header: {
        'content-type': 'application/json'
      },
      success: function (param) {
        //调起微信小程序输入密码支付弹窗进行支付
        that.zf(param);
      },
      fail: function(error) {
        console.info(error);
      }
    })
  },
  //调起微信小程序输入密码支付弹窗进行支付
  zf: function (param) {
    console.log("发起支付")
    wx.requestPayment({
      timeStamp: param.data.timeStamp, //北京时间 时间戳
      nonceStr: param.data.nonceStr, //随机字符串,不得长于32位
      package: param.data.package, //小程序下单返回的预支付标识 prepay_id
      signType: param.data.signType, //签名类型
      paySign: param.data.paySign,  //签名签名,使用字段`appid`、`timeStamp`、`nonceStr`、`package`计算得出的签名值,签名所使用的`appid`,为【小程序下单】时传入的`appid`,微信支付会校验下单与调起支付所使用的`appid`的一致性。
      success: function (res) {
        console.log(res);
      },
      fail: function (res) {
        console.log(res);
      },
      complete: function (res) {
        console.log(res)
      }
    })
  }
})

三、效果实现

以上就是微信小程序支付的全部流程了!!!

相关推荐
5967851544 小时前
DotNetty ChannelRead接收数据为null
tcp/ip·c#
丁总学Java4 小时前
微信小程序-npm支持-如何使用npm包
前端·微信小程序·npm·node.js
weixin_464078075 小时前
C#串口温度读取
开发语言·c#
明耀7 小时前
WPF RadioButton 绑定boolean值
c#·wpf
一丝晨光9 小时前
Java、PHP、ASP、JSP、Kotlin、.NET、Go
java·kotlin·go·php·.net·jsp·asp
Death2009 小时前
Qt 中的 QListWidget、QTreeWidget 和 QTableWidget:简化的数据展示控件
c语言·开发语言·c++·qt·c#
Death20010 小时前
Qt 3D、QtQuick、QtQuick 3D 和 QML 的关系
c语言·c++·qt·3d·c#
yufei-coder10 小时前
C#基础语法
开发语言·c#·.net
yngsqq10 小时前
031集——文本文件按空格分行——C#学习笔记
笔记·学习·c#
Mudrock__11 小时前
前后端传输文件(图片)
vue·.net