微信小程序支付功能的開發的時候坑比較多,不過對於錢的事謹慎也是好事。網上關於小程序支付的實例不少,可是大多多少有些問題,C#開發的更少。此篇文檔的目的是講開發過程當中遇到的問題作一個備註,也方便其餘開發的同窗做爲參考!php
一、首先建議把官方文檔支付部分看上三遍,每一個細節都不要放過,由於任何一個點和微信要求不符都會致使支付不成功。https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=3_1html
二、通過驗證的微信支付功能,會須要一些商戶號、支付祕鑰等,不要搞混。web
三、常常遇到的是「簽名錯誤」,請仔細看須要傳送的xml參數及取值規則是否符合微信規則。微信有個驗證工具能夠驗證發送的xml字段是否合法。算法
下面上代碼:小程序
web.config微信小程序
<add key="ConnectionString" value="server=127.0.0.1;database=;uid=sa;pwd="/> <add key="ConnectionString2" value="server=127.0.0.1;database=codematic2;uid=sa;pwd=1"/> <add key="appid" value=""/>//appid <add key="secret" value=""/>//小程序祕鑰 <add key="mch_id" value=""/>//商戶號 <add key="key" value=""/>//支付祕鑰 <add key="ip" value=""/>//服務器IP <add key="PayResulturl" value=""/>//微信返回接收信息的url地址 </appSettings>
支付後臺xiadan.ashxapi
<%@ WebHandler Language="C#" Class="xiadan" %> using System; using System.Web; using System.Net; using System.IO; using System.Configuration; using Maticsoft.Model; using Maticsoft.BLL; using System.Security.Cryptography; using System.Text; using System.Xml.Serialization; using System.Xml; using System.Collections.Generic; using System.Data; using System.Net.Security; using System.Security.Cryptography.X509Certificates; using System.Linq; using Newtonsoft.Json; public class xiadan : IHttpHandler { public void ProcessRequest(HttpContext context) { context.Response.ContentType = "text/plain"; string openid = context.Request.Params["openid"]; string ordertime = context.Request.Params["ordertime"]; string appid = ConfigurationManager.AppSettings["appid"]; string secret = ConfigurationManager.AppSettings["secret"]; string key = ConfigurationManager.AppSettings["key"]; string mch_id = ConfigurationManager.AppSettings["mch_id"]; string ip = ConfigurationManager.AppSettings["ip"]; string PayResulturl = ConfigurationManager.AppSettings["PayResulturl"]; string roomid = context.Request.Params["roomid"]; string aa = "-押金";////商品描述交易字段格式根據不一樣的應用場景按照如下格式:APP——需傳入應用市場上的APP名字-實際商品名稱,每天愛消除-遊戲充值。 string strcode = aa; byte[] buffer = Encoding.UTF8.GetBytes(strcode); string body = Encoding.UTF8.GetString(buffer, 0, buffer.Length); string totalfee = context.Request.Params["totalfee"]; string output = ""; if ((context.Request.Params["openid"] != null) && (context.Request.Params["openid"] != "")) { //OrderInfo order = new OrderInfo(); //order.appid = appid; System.Random Random = new System.Random(); var dic = new Dictionary<string, string> { {"appid", appid}, {"mch_id", mch_id}, {"nonce_str", GetRandomString(20)/*Random.Next().ToString()*/}, {"body",body}, {"out_trade_no",roomid + DateTime.Now.ToString("yyyyMMddHHmmssfff") + Random.Next(999).ToString()},//商戶本身的訂單號碼 {"total_fee",totalfee}, {"spbill_create_ip",ip},//服務器的IP地址 {"notify_url",PayResulturl},//異步通知的地址,不能帶參數 {"trade_type","JSAPI" }, {"openid",openid} }; //加入簽名 dic.Add("sign", GetSignString(dic)); var sb = new StringBuilder(); sb.Append("<xml>"); foreach (var d in dic) { sb.Append("<" + d.Key + ">" + d.Value + "</" + d.Key + ">"); } sb.Append("</xml>"); var xml = new XmlDocument(); // xml.LoadXml(GetPostString("https://api.mch.weixin.qq.com/pay/unifiedorder", sb.ToString())); CookieCollection coo = new CookieCollection(); Encoding en = Encoding.GetEncoding("UTF-8"); HttpWebResponse response = CreatePostHttpResponse("https://api.mch.weixin.qq.com/pay/unifiedorder", sb.ToString(), en); //打印返回值 Stream stream = response.GetResponseStream(); //獲取響應的字符串流 StreamReader sr = new StreamReader(stream); //建立一個stream讀取流 string html = sr.ReadToEnd(); //從頭讀到尾,放到字符串html //Console.WriteLine(html); xml.LoadXml(html); //對請求返回值 進行處理 var root = xml.DocumentElement; DataSet ds = new DataSet(); StringReader stram = new StringReader(html); XmlTextReader reader = new XmlTextReader(stram); ds.ReadXml(reader); string return_code = ds.Tables[0].Rows[0]["return_code"].ToString(); if (return_code.ToUpper() == "SUCCESS") { //通訊成功 string result_code = ds.Tables[0].Rows[0]["result_code"].ToString();//業務結果 if (result_code.ToUpper() == "SUCCESS") { var res = new Dictionary<string, string> { {"appId", appid}, {"timeStamp", GetTimeStamp()}, {"nonceStr", dic["nonce_str"]}, {"package", "prepay_id="+ds.Tables[0].Rows[0]["prepay_id"].ToString()}, {"signType", "MD5"} }; //在服務器上簽名 res.Add("paySign", GetSignString(res)); // string signapp = res.ToString(); string signapp = JsonConvert.SerializeObject(res); if ((context.Request.Params["openid"] != null) && (context.Request.Params["openid"] != "")) { //存儲訂單信息 Maticsoft.Model.order_history oh = new Maticsoft.Model.order_history(); //oh.shop_id = oh.room_id = Convert.ToInt32(roomid); oh.pay_price = Convert.ToDecimal(totalfee); oh.out_trade_no = dic["out_trade_no"]; oh.order_timestart = Convert.ToDateTime(ordertime); oh.openid = openid; oh.creating_date = DateTime.Now; Maticsoft.BLL.order_history bll = new Maticsoft.BLL.order_history(); bll.Add(oh); } context.Response.Write(signapp); } } } context.Response.Write(output); } public bool IsReusable { get { return false; } } public string GetMd5Hash(String input) { if (input == null) { return null; } MD5 md5Hash = MD5.Create(); // 將輸入字符串轉換爲字節數組並計算哈希數據 byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input)); // 建立一個 Stringbuilder 來收集字節並建立字符串 StringBuilder sBuilder = new StringBuilder(); // 循環遍歷哈希數據的每個字節並格式化爲十六進制字符串 for (int i = 0; i < data.Length; i++) { sBuilder.Append(data[i].ToString()); } // 返回十六進制字符串 return sBuilder.ToString(); } /// <summary> /// 對象序列化成 XML String /// </summary> public static string XmlSerialize<T>(T obj) { string xmlString = string.Empty; XmlSerializer xmlSerializer = new XmlSerializer(typeof(T)); using (MemoryStream ms = new MemoryStream()) { xmlSerializer.Serialize(ms, obj); xmlString = Encoding.UTF8.GetString(ms.ToArray()); } return xmlString; } /// <summary> /// 從字符串裏隨機獲得,規定個數的字符串. /// </summary> /// <param name="allChar"></param> /// <param name="CodeCount"></param> /// <returns></returns> public static string GetRandomString(int CodeCount) { string allChar = "1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,i,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z"; string[] allCharArray = allChar.Split(','); string RandomCode = ""; int temp = -1; Random rand = new Random(); for (int i = 0; i < CodeCount; i++) { if (temp != -1) { rand = new Random(temp * i * ((int)DateTime.Now.Ticks)); } int t = rand.Next(allCharArray.Length -