C#, WeChat applet payment interface

Recently, there is a project involving the payment function of WeChat applet. Here, Xiaomo will record the steps that need to be paid attention to, and give it to friends in need.

1. Preliminary preparation

Need to prepare in advance [Global Variables]

public static string _appid = "xxxxxxxx";//appid
public static string appsecret = "xxxxxxxxx";//小程序密钥
public static string _mch_id = "xxxxxx";//商户号
public static string _key = "xxxxxxxxxxxxxxx";//商户平台设置的密钥key

Here you can find the company to ask for it, usually it will provide it, if you develop it yourself, you can go to the WeChat public platform to apply, the entrance:   https://mp.weixin.qq.com

       //模拟wx统一下单 openid(前台获取)
        public string getda(dynamic _)
        {
            wx_parameter req = this.Bind<wx_parameter>();//这里是小程序传递的参数
            //支付费用
            double  total_fee =double.Parse(req.total_fee);//支付金额
            //获取openid
            var authorizeList = xx.GetList(new { applet_token = token }.ToJson()).ToList();
            var user = xxx.GetList(new { open_id = authorizeList[0].openid }.ToJson()).ToList()[0];
            string openid = user.open_id; //获取openid的方法可以百度下,https://www.cnblogs.com/dujian123/p/11184781.html

            return Getprepay_id(_appid, "shanghaifendian", "monixiaofei", _mch_id, GetRandomString(30), "http://www.weixin.qq.com/wxpay/pay.php", openid, getRandomTime(), total_fee);
        }

Get openid: https://www.cnblogs.com/dujian123/p/11184781.html

   /// <summary>
        /// 微信统一下单获取prepay_id & 再次签名返回数据
        /// 屡一下思路:通过参数请求统一下单的链接,返回的xml解析后,判断成功后,进行二次签名,最终返回给小程序前端。
        /// </summary>
        /// <param name="appid">appid</param>
        /// <param name="attach">附加数据(描述)</param>
        /// <param name="body">商品描述</param>
        /// <param name="mch_id">商户号</param>
        /// <param name="nonce_str">随机字符串,不长于32位。  </param>
        /// <param name="notify_url">通知地址</param>
        /// <param name="openid">openid</param>
        /// <param name="bookingNo">商户订单号</param>
        /// <param name="total_fee">支付金额单位为(分)比如一元等于100分</param>
        /// <returns></returns>
        private static string Getprepay_id(string appid, string attach, string body, string mch_id, string nonce_str, string notify_url, string openid, string bookingNo, double total_fee)
        {
            var url = "https://api.mch.weixin.qq.com/pay/unifiedorder";//微信统一下单请求地址
            string strA = "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";
            string strk = strA + "&key=" + _key;  //key为商户平台设置的密钥key(假)
            string strMD5 = MD5(strk).ToUpper();//MD5签名
            //string strHash=HmacSHA256("sha256",strmd5).ToUpper();   //签名方式只需一种(MD5 或 HmacSHA256     【支付文档需仔细看】)
            //签名
            //终端ip  
            string spbill_create_ip = getspbill_create_ip();
            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>"+ spbill_create_ip + "</spbill_create_ip>";//终端IP  --用户ip
            formData += "<total_fee>" + Convert.ToInt32(total_fee * 100).ToString() + "</total_fee>";//支付金额单位为(分)
            formData += "<trade_type>JSAPI</trade_type>";//交易类型(JSAPI--公众号支付)
            formData += "<sign>" + strMD5 + "</sign>"; //签名
            formData += "</xml>";
   
            //请求数据
            var getdata = sendPost(url, formData);
   
            //获取xml数据
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(getdata);
            wx w = new wx();
            if (doc != null)
            {
                XmlNode xmlNode = doc["xml"];
                if (xmlNode["return_code"].InnerText.Equals("SUCCESS") && xmlNode["result_code"].InnerText.Equals("SUCCESS"))
                {
                    #region 再次签名
                    //时间戳
                    string _time = getTime().ToString();
                    //prepay_id
                    string prepay_id = xmlNode["prepay_id"].InnerText;
                    //再次签名返回数据至小程序
                    string strB = "appId=" + appid + "&nonceStr=" + nonce_str + "&package=prepay_id=" + prepay_id + "&signType=MD5&timeStamp=" + _time + "&key=" + _key;

                    w.Result = "Success";
                    w.errmsg = "统一下单成功";
                    w.timeStamp = _time;
                    w.nonceStr = nonce_str;
                    w.package = "prepay_id=" + prepay_id;
                    w.paySign = MD5(strB).ToUpper(); ;
                    w.signType = "MD5";
                    //向小程序返回json数据
                    #endregion
                }
                else
                {
                    w.Result = "Error";
                    w.errmsg = xmlNode["return_msg"].InnerText;
                }
            }
            else
            {
                w.Result = "Error";
                w.errmsg ="统一下单失败";
            }      
            return JsonConvert.SerializeObject(w);
        }

The method of generating random string and signature encryption can refer to the following

      /// <summary>
      /// 生成随机串    
      /// </summary>
      /// <param name="length">字符串长度</param>
      /// <returns></returns>
      private static string GetRandomString(int length)
      {
          const string key = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
          if (length< 1)
              return string.Empty;
 
          Random rnd = new Random();
          byte[] buffer = new byte[8];
 
          ulong bit = 31;
          ulong result = 0;
          int index = 0;
          StringBuilder sb = new StringBuilder((length / 5 + 1) * 5);
 
          while (sb.Length<length)
          {
              rnd.NextBytes(buffer);
 
              buffer[5] = buffer[6] = buffer[7] = 0x00;
              result = BitConverter.ToUInt64(buffer, 0);
 
              while (result > 0 && sb.Length<length)
              {
                  index = (int) (bit & result);
                  sb.Append(key[index]);
                  result = result >> 5;
              }
          }
          return sb.ToString();
      }

        /// <summary>
        /// 获取终端ip,访问者ip
        /// </summary>
        /// <param name="_"></param>
        /// <returns></returns>
        private static string  getspbill_create_ip()
        {
            string url = "https://pv.sohu.com/cityjson?ie=utf-8";
            using (var httpClient = new HttpClient())
            {
                httpClient.DefaultRequestHeaders.Add("Accept", "application/json");//设置请求头
                var url1 = new Uri(url);
                // response
                var response = httpClient.GetAsync(url1).Result;
                var data = response.Content.ReadAsStringAsync().Result.Trim('"');
                data = data.TrimEnd(';').Split('=')[1].ToString();
                JObject obj = (JObject)JsonConvert.DeserializeObject(data);
                string spbill_create_ip = obj["cip"].ToString();
                return spbill_create_ip;
            }
        }

        /// <summary>
        /// 获取时间戳,时间戳从1970年1月1日00:00:00至今的秒数,即当前的时间
        /// </summary>
        /// <returns></returns>
        private static long getTime()
       {
           TimeSpan cha = (DateTime.Now - TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1)));
           long t = (long)cha.TotalSeconds;
           return t;
       }
     /// <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;
        }
      /// <summary>
        /// HMAC-SHA256签名方式
        /// </summary>
        /// <param name="message"></param>
        /// <param name="secret"></param>
        /// <returns></returns>
        private static string HmacSHA256(string message, string secret)
        {
            secret = secret ?? "";
            var encoding = new System.Text.UTF8Encoding();
            byte[] keyByte = encoding.GetBytes(secret);
            byte[] messageBytes = encoding.GetBytes(message);
            using (var hmacsha256 = new HMACSHA256(keyByte))
            {
                byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
                return Convert.ToBase64String(hashmessage);
            }
        }


    /// <summary>
        /// wx统一下单请求数据
        /// </summary>
        /// <param name="URL">请求地址</param>
        /// <param name="urlArgs">参数</param>
        /// <returns></returns>
        private static string sendPost(string URL, string urlArgs)
        {
            System.Net.WebClient wCient = new System.Net.WebClient();
            wCient.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
            //byte[] postData = System.Text.Encoding.ASCII.GetBytes(urlArgs);  如果微信签名中有中文会签名失败
        byte[] postData = System.Text.Encoding.UTF8.GetBytes(urlArgs);     
            byte[] responseData = wCient.UploadData(URL, "POST", postData);
            string returnStr = System.Text.Encoding.UTF8.GetString(responseData);//返回接受的数据 
            return returnStr;
         }


    /// <summary>
    /// 生成订单号【这里可以用一个订单表记录订单号】
    /// </summary>
    /// <returns></returns>
    private static string getRandomTime()
      {
          Random rd = new Random();//用于生成随机数
          string DateStr = DateTime.Now.ToString("yyyyMMddHHmmssMM");//日期
          string str = DateStr + rd.Next(10000).ToString().PadLeft(4, '0');//带日期的随机数
          return str;
      }

The following are the required entity classes:

    /// <summary>
    /// 小程序调用后台
    /// </summary>
    public class wx_parameter
    {
        /// <summary>
        /// 支付费用
        /// </summary>
        public string total_fee { get; set; }
      
    }
    /// <summary>
    /// 返回给小程序
    /// </summary>
    public class wx
    {
        /// <summary>
        /// 返回结果【Success/Error】
        /// </summary>
        public string Result { get; set; }
        /// <summary>
        /// 描述
        /// </summary>
        public string errmsg { get; set; }

        /// <summary>
        /// 时间戳
        /// </summary>
        public string  timeStamp { get;set;}
        /// <summary>
        /// 随机数
        /// </summary>
        public string nonceStr { get; set; }
        /// <summary>
        /// 同一下单接口的prepay_id参数
        /// </summary>
        public string package { get; set; }
       /// <summary>
       /// 第二次签名
       /// </summary>
        public string paySign { get; set; }
       /// <summary>
       /// 签名方式
       /// </summary>
        public string signType { get; set; }

    }

Finally, you need to make a callback to modify the status of the order number after the payment is successful, etc. (according to your own business needs)

Here are some reference documents:

"WeChat Official Document: Payment Part"

https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=3_1

"WeChat Official Document: Unified Payment"

https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1

Those who are interested can pay attention to " Ink Direct ", there are many free programming materials to receive~

Guess you like

Origin blog.csdn.net/huxinyu0208/article/details/109183196