微信小程序支付功能 C# .NET開發

微信小程序支付功能的開發的時候坑比較多,不過對於錢的事謹慎也是好事。網上關於小程序支付的實例不少,可是大多多少有些問題,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 - 1); while (temp == t) { t = rand.Next(allCharArray.Length - 1); } temp = t; RandomCode += allCharArray[t]; } return RandomCode; } public static string GetWebClientIp() { string userIP = "IP"; try { if (System.Web.HttpContext.Current == null || System.Web.HttpContext.Current.Request == null || System.Web.HttpContext.Current.Request.ServerVariables == null) return ""; string CustomerIP = ""; //CDN加速後取到的IP CustomerIP = System.Web.HttpContext.Current.Request.Headers["Cdn-Src-Ip"]; if (!string.IsNullOrEmpty(CustomerIP)) { return CustomerIP; } CustomerIP = System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"]; if (!String.IsNullOrEmpty(CustomerIP)) return CustomerIP; if (System.Web.HttpContext.Current.Request.ServerVariables["HTTP_VIA"] != null) { CustomerIP = System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"]; if (CustomerIP == null) CustomerIP = System.Web.HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"]; } else { CustomerIP = System.Web.HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"]; } if (string.Compare(CustomerIP, "unknown", true) == 0) return System.Web.HttpContext.Current.Request.UserHostAddress; return CustomerIP; } catch { } return userIP; } private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors) { return true; //老是接受 } public static HttpWebResponse CreatePostHttpResponse(string url, string datas, Encoding charset) { HttpWebRequest request = null; //HTTPSQ請求 ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult); request = WebRequest.Create(url) as HttpWebRequest; request.ProtocolVersion = HttpVersion.Version10; request.Method = "POST"; request.ContentType = "application/x-www-form-urlencoded"; //若是須要POST數據 //if (!(parameters == null || parameters.Count == 0)) //{ StringBuilder buffer = new StringBuilder(); //int i = 0; //foreach (string key in parameters.Keys) //{ // if (i > 0) // { // buffer.AppendFormat("&{0}={1}", key, parameters[key]); // } // else // { // buffer.AppendFormat("{0}={1}", key, parameters[key]); // } // i++; //} buffer.AppendFormat(datas); byte[] data = charset.GetBytes(buffer.ToString()); using (Stream stream = request.GetRequestStream()) { stream.Write(data, 0, data.Length); } //} return request.GetResponse() as HttpWebResponse; } public string GetSignString(Dictionary<string, string> dic) { string key = System.Web.Configuration.WebConfigurationManager.AppSettings["key"].ToString();//商戶平臺 API安全裏面設置的KEY 32位長度 //排序 dic = dic.OrderBy(d => d.Key).ToDictionary(d => d.Key, d => d.Value); //鏈接字段 var sign = dic.Aggregate("", (current, d) => current + (d.Key + "=" + d.Value + "&")); sign += "key=" + key; //MD5 // sign = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(sign, "MD5").ToUpper(); System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create(); sign = BitConverter.ToString(md5.ComputeHash(Encoding.UTF8.GetBytes(sign))).Replace("-", null); return sign; } /// <summary> /// 獲取時間戳 /// </summary> /// <returns></returns> public static string GetTimeStamp() { TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0); return Convert.ToInt64(ts.TotalSeconds).ToString(); } }




 

      微信返回信息接收後臺頁面notify_url.ashx數組

 

<%@ WebHandler Language="C#" Class="notify_url" %> using System; using System.Web; using System.Collections.Generic; using System.Data; using System.IO; using System.Text; using System.Xml; using System.Net; public class notify_url : IHttpHandler { public string return_result = ""; public void ProcessRequest(HttpContext context) { context.Response.ContentType = "text/plain"; context.Response.Write("Hello World"); String xmlData = getPostStr();//獲取請求數據 if (xmlData == "") { } else { var dic = new Dictionary<string, string> { {"return_code", "SUCCESS"}, {"return_msg","OK"} }; var sb = new StringBuilder(); sb.Append("<xml>"); foreach (var d in dic) { sb.Append("<" + d.Key + ">" + d.Value + "</" + d.Key + ">"); } sb.Append("</xml>"); //把數據從新返回給客戶端 DataSet ds = new DataSet(); StringReader stram = new StringReader(xmlData); XmlTextReader datareader = new XmlTextReader(stram); ds.ReadXml(datareader); if (ds.Tables[0].Rows[0]["return_code"].ToString() == "SUCCESS") { string wx_appid = "";//微信開放平臺審覈經過的應用APPID string wx_mch_id = "";//微信支付分配的商戶號 string wx_nonce_str = "";// 隨機字符串,不長於32位 string wx_sign = "";//簽名,詳見簽名算法 string wx_result_code = "";//SUCCESS/FAIL string wx_return_code = ""; string wx_openid = "";//用戶在商戶appid下的惟一標識 string wx_is_subscribe = "";//用戶是否關注公衆帳號,Y-關注,N-未關注,僅在公衆帳號類型支付有效 string wx_trade_type = "";// APP string wx_bank_type = "";// 銀行類型,採用字符串類型的銀行標識,銀行類型見銀行列表 string wx_fee_type = "";// 貨幣類型,符合ISO4217標準的三位字母代碼,默認人民幣:CNY,其餘值列表詳見貨幣類型 string wx_transaction_id = "";//微信支付訂單號 string wx_out_trade_no = "";//商戶系統的訂單號,與請求一致。 string wx_time_end = "";// 支付完成時間,格式爲yyyyMMddHHmmss,如2009年12月25日9點10分10秒錶示爲20091225091010。其餘詳見時間規則 int wx_total_fee = -1;// 訂單總金額,單位爲分 int wx_cash_fee = -1;//現金支付金額訂單現金支付金額,詳見支付金額 #region 數據解析 //列 是否存在 string signstr = "";//須要前面的字符串 //wx_appid if (ds.Tables[0].Columns.Contains("appid")) { wx_appid = ds.Tables[0].Rows[0]["appid"].ToString(); if (!string.IsNullOrEmpty(wx_appid)) { signstr += "appid=" + wx_appid; } } //wx_bank_type if (ds.Tables[0].Columns.Contains("bank_type")) { wx_bank_type = ds.Tables[0].Rows[0]["bank_type"].ToString(); if (!string.IsNullOrEmpty(wx_bank_type)) { signstr += "&bank_type=" + wx_bank_type; } } //wx_cash_fee if (ds.Tables[0].Columns.Contains("cash_fee")) { wx_cash_fee = Convert.ToInt32(ds.Tables[0].Rows[0]["cash_fee"].ToString()); signstr += "&cash_fee=" + wx_cash_fee; } //wx_fee_type if (ds.Tables[0].Columns.Contains("fee_type")) { wx_fee_type = ds.Tables[0].Rows[0]["fee_type"].ToString(); if (!string.IsNullOrEmpty(wx_fee_type)) { signstr += "&fee_type=" + wx_fee_type; } } //wx_is_subscribe if (ds.Tables[0].Columns.Contains("is_subscribe")) { wx_is_subscribe = ds.Tables[0].Rows[0]["is_subscribe"].ToString(); if (!string.IsNullOrEmpty(wx_is_subscribe)) { signstr += "&is_subscribe=" + wx_is_subscribe; } } //wx_mch_id if (ds.Tables[0].Columns.Contains("mch_id")) { wx_mch_id = ds.Tables[0].Rows[0]["mch_id"].ToString(); if (!string.IsNullOrEmpty(wx_mch_id)) { signstr += "&mch_id=" + wx_mch_id; } } //wx_nonce_str if (ds.Tables[0].Columns.Contains("nonce_str")) { wx_nonce_str = ds.Tables[0].Rows[0]["nonce_str"].ToString(); if (!string.IsNullOrEmpty(wx_nonce_str)) { signstr += "&nonce_str=" + wx_nonce_str; } } //wx_openid if (ds.Tables[0].Columns.Contains("openid")) { wx_openid = ds.Tables[0].Rows[0]["openid"].ToString(); if (!string.IsNullOrEmpty(wx_openid)) { signstr += "&openid=" + wx_openid; } } //wx_out_trade_no if (ds.Tables[0].Columns.Contains("out_trade_no")) { wx_out_trade_no = ds.Tables[0].Rows[0]["out_trade_no"].ToString(); if (!string.IsNullOrEmpty(wx_out_trade_no)) { signstr += "&out_trade_no=" + wx_out_trade_no; } } //wx_result_code if (ds.Tables[0].Columns.Contains("result_code")) { wx_result_code = ds.Tables[0].Rows[0]["result_code"].ToString(); if (!string.IsNullOrEmpty(wx_result_code)) { signstr += "&result_code=" + wx_result_code; } } //wx_result_code if (ds.Tables[0].Columns.Contains("return_code")) { wx_return_code = ds.Tables[0].Rows[0]["return_code"].ToString(); if (!string.IsNullOrEmpty(wx_return_code)) { signstr += "&return_code=" + wx_return_code; } } //wx_sign if (ds.Tables[0].Columns.Contains("sign")) { wx_sign = ds.Tables[0].Rows[0]["sign"].ToString(); //if (!string.IsNullOrEmpty(wx_sign)) //{ // signstr += "&sign=" + wx_sign; //} } //wx_time_end if (ds.Tables[0].Columns.Contains("time_end")) { wx_time_end = ds.Tables[0].Rows[0]["time_end"].ToString(); if (!string.IsNullOrEmpty(wx_time_end)) { signstr += "&time_end=" + wx_time_end; } } //wx_total_fee if (ds.Tables[0].Columns.Contains("total_fee")) { wx_total_fee = Convert.ToInt32(ds.Tables[0].Rows[0]["total_fee"].ToString()); signstr += "&total_fee=" + wx_total_fee; } //wx_trade_type if (ds.Tables[0].Columns.Contains("trade_type")) { wx_trade_type = ds.Tables[0].Rows[0]["trade_type"].ToString(); if (!string.IsNullOrEmpty(wx_trade_type)) { signstr += "&trade_type=" + wx_trade_type; } } //wx_transaction_id if (ds.Tables[0].Columns.Contains("transaction_id")) { wx_transaction_id = ds.Tables[0].Rows[0]["transaction_id"].ToString(); if (!string.IsNullOrEmpty(wx_transaction_id)) { signstr += "&transaction_id=" + wx_transaction_id; } } #endregion //追加key 密鑰 signstr += "&key=" + System.Web.Configuration.WebConfigurationManager.AppSettings["key"].ToString(); //簽名正確 string orderStrwhere = "ordernumber='" + wx_out_trade_no + "'"; if (wx_sign == System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(signstr, "MD5").ToUpper()) { //簽名正確 處理訂單操做邏輯 } else { //追加備註信息 } } else { // 返回信息,如非空,爲錯誤緣由 簽名失敗 參數格式校驗錯誤 string return_msg = ds.Tables[0].Rows[0]["return_msg"].ToString(); } return_result = sb.ToString(); } } public bool IsReusable { get { return false; } } //得到Post過來的數據 public string getPostStr() { Int32 intLen = Convert.ToInt32(System.Web.HttpContext.Current.Request.InputStream.Length); byte[] b = new byte[intLen]; System.Web.HttpContext.Current.Request.InputStream.Read(b, 0, intLen); return System.Text.Encoding.UTF8.GetString(b); } }
相關文章
相關標籤/搜索