微信小程序支付功能的开发的时候坑比较多,不过对于钱的事谨慎也是好事。网上关于小程序支付的实例很多,但是大多多少有些问题,C#开发的更少。此篇文档的目的是讲开发过程中遇到的问题做一个备注,也方便其他开发的同学作为参考!
1、首先建议把官方文档支付部分看上三遍,每个细节都不要放过,因为任何一个点和微信要求不符都会导致支付不成功。https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=3_1
2、经过验证的微信支付功能,会需要一些商户号、支付秘钥等,不要搞混。
3、经常遇到的是“签名错误”,请仔细看需要传送的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.ashx
<%@ 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 =