微信小程序支付功能 C# .NET开发

微信小程序支付功能的开发的时候坑比较多,不过对于钱的事谨慎也是好事。网上关于小程序支付的实例很多,但是大多多少有些问题,C#开发的更少。此篇文档的目的是讲开发过程中遇到的问题做一个备注,也方便其他开发的同学作为参考!


       1、首先建议把官方文档支付部分看上三遍,每个细节都不要放过,因为任何一个点和微信要求不符都会导致支付不成功。https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=3_1

      2、经过验证的微信支付功能,会需要一些商户号、支付秘钥等,不要搞混。

     3、经常遇到的是“签名错误”,请仔细看需要传送的xml参数及取值规则是否符合微信规则。微信有个验证工具可以验证发送的xml字段是否合法。


下面上代码:


web.config

[csharp]  view plain  copy
  1.   <add key="ConnectionString" value="server=127.0.0.1;database=;uid=sa;pwd="/>  
  2.   <add key="ConnectionString2" value="server=127.0.0.1;database=codematic2;uid=sa;pwd=1"/>  
  3.   <add key="appid" value=""/>//appid  
  4.   <add key="secret" value=""/>//小程序秘钥  
  5.   <add key="mch_id" value=""/>//商户号  
  6.   <add key="key" value=""/>//支付秘钥  
  7.   <add key="ip" value=""/>//服务器IP  
  8.   <add key="PayResulturl" value=""/>//微信返回接收信息的url地址  
  9. </appSettings>  
支付后台xiadan.ashx

[csharp]  view plain  copy
  1. <%@ WebHandler Language="C#" Class="xiadan" %>  
  2.   
  3. using System;  
  4. using System.Web;  
  5. using System.Net;  
  6. using System.IO;  
  7. using System.Configuration;  
  8. using Maticsoft.Model;  
  9. using Maticsoft.BLL;  
  10. using System.Security.Cryptography;  
  11. using System.Text;  
  12. using System.Xml.Serialization;  
  13. using System.Xml;  
  14. using System.Collections.Generic;  
  15. using System.Data;  
  16. using System.Net.Security;  
  17. using System.Security.Cryptography.X509Certificates;  
  18. using System.Linq;  
  19. using Newtonsoft.Json;  
  20.   
  21. public class xiadan : IHttpHandler  
  22. {  
  23.   
  24.     public void ProcessRequest(HttpContext context)  
  25.     {  
  26.         context.Response.ContentType = "text/plain";  
  27.         string openid = context.Request.Params["openid"];  
  28.         string ordertime = context.Request.Params["ordertime"];  
  29.   
  30.         string appid = ConfigurationManager.AppSettings["appid"];  
  31.         string secret = ConfigurationManager.AppSettings["secret"];  
  32.         string key = ConfigurationManager.AppSettings["key"];  
  33.         string mch_id = ConfigurationManager.AppSettings["mch_id"];  
  34.         string ip = ConfigurationManager.AppSettings["ip"];  
  35.         string PayResulturl = ConfigurationManager.AppSettings["PayResulturl"];  
  36.         string roomid = context.Request.Params["roomid"];  
  37.         string aa = "-押金";////商品描述交易字段格式根据不同的应用场景按照以下格式:APP——需传入应用市场上的APP名字-实际商品名称,天天爱消除-游戏充值。  
  38.   
  39.         string strcode = aa;  
  40.         byte[] buffer = Encoding.UTF8.GetBytes(strcode);  
  41.         string body = Encoding.UTF8.GetString(buffer, 0, buffer.Length);  
  42.         string totalfee = context.Request.Params["totalfee"];  
  43.         string output = "";  
  44.         if ((context.Request.Params["openid"] != null) && (context.Request.Params["openid"] != ""))  
  45.         {  
  46.             //OrderInfo order = new OrderInfo();  
  47.   
  48.             //order.appid = appid;  
  49.   
  50.             System.Random Random = new System.Random();  
  51.   
  52.   
  53.   
  54.             var dic = new Dictionary<stringstring>  
  55. {  
  56.     {"appid", appid},  
  57.     {"mch_id", mch_id},  
  58.     {"nonce_str", GetRandomString(20)/*Random.Next().ToString()*/},  
  59.     {"body",body},  
  60.     {"out_trade_no",roomid + DateTime.Now.ToString("yyyyMMddHHmmssfff") + Random.Next(999).ToString()},//商户自己的订单号码  
  61.     {"total_fee",totalfee},  
  62.     {"spbill_create_ip",ip},//服务器的IP地址  
  63.     {"notify_url",PayResulturl},//异步通知的地址,不能带参数  
  64.     {"trade_type","JSAPI" },  
  65.     {"openid",openid}  
  66. };  
  67.       //加入签名  
  68.             dic.Add("sign", GetSignString(dic));  
  69.   
  70.             var sb = new StringBuilder();  
  71.             sb.Append("<xml>");  
  72.   
  73.   
  74.             foreach (var d in dic)  
  75.             {  
  76.                 sb.Append("<" + d.Key + ">" + d.Value + "</" + d.Key + ">");  
  77.             }  
  78.             sb.Append("</xml>");  
  79.             var xml = new XmlDocument();  
  80.             //  xml.LoadXml(GetPostString("https://api.mch.weixin.qq.com/pay/unifiedorder", sb.ToString()));  
  81.             CookieCollection coo = new CookieCollection();  
  82.             Encoding en = Encoding.GetEncoding("UTF-8");  
  83.   
  84.             HttpWebResponse response = CreatePostHttpResponse("https://api.mch.weixin.qq.com/pay/unifiedorder", sb.ToString(), en);  
  85.             //打印返回值  
  86.             Stream stream = response.GetResponseStream();   //获取响应的字符串流  
  87.             StreamReader sr = new StreamReader(stream); //创建一个stream读取流  
  88.             string html = sr.ReadToEnd();   //从头读到尾,放到字符串html  
  89.                                             //Console.WriteLine(html);  
  90.             xml.LoadXml(html);  
  91.             //对请求返回值 进行处理  
  92.   
  93.             var root = xml.DocumentElement;  
  94.   
  95.             DataSet ds = new DataSet();  
  96.             StringReader stram = new StringReader(html);  
  97.             XmlTextReader reader = new XmlTextReader(stram);  
  98.             ds.ReadXml(reader);  
  99.             string return_code = ds.Tables[0].Rows[0]["return_code"].ToString();  
  100.             if (return_code.ToUpper() == "SUCCESS")  
  101.             {  
  102.                 //通信成功  
  103.                 string result_code = ds.Tables[0].Rows[0]["result_code"].ToString();//业务结果  
  104.                 if (result_code.ToUpper() == "SUCCESS")  
  105.                 {  
  106.                     var res = new Dictionary<stringstring>  
  107. {  
  108.     {"appId", appid},  
  109.     {"timeStamp", GetTimeStamp()},  
  110.     {"nonceStr", dic["nonce_str"]},  
  111.     {"package",  "prepay_id="+ds.Tables[0].Rows[0]["prepay_id"].ToString()},  
  112.     {"signType""MD5"}  
  113. };  
  114.   
  115.                     //在服务器上签名  
  116.                     res.Add("paySign", GetSignString(res));  
  117.                     // string signapp = res.ToString();  
  118.                     string signapp = JsonConvert.SerializeObject(res);  
  119.                     if ((context.Request.Params["openid"] != null) && (context.Request.Params["openid"] != ""))  
  120.                     {   
  121.                     //存储订单信息  
  122.                     Maticsoft.Model.order_history oh = new Maticsoft.Model.order_history();  
  123.                     //oh.shop_id =  
  124.                     oh.room_id = Convert.ToInt32(roomid);  
  125.                     oh.pay_price = Convert.ToDecimal(totalfee);  
  126.                     oh.out_trade_no = dic["out_trade_no"];  
  127.                     oh.order_timestart = Convert.ToDateTime(ordertime);  
  128.                     oh.openid = openid;  
  129.                     oh.creating_date = DateTime.Now;  
  130.   
  131.                     Maticsoft.BLL.order_history bll = new Maticsoft.BLL.order_history();  
  132.                     bll.Add(oh);  
  133.   
  134.                 }  
  135.                 context.Response.Write(signapp);  
  136.             }  
  137.         }  
  138.   
  139.   
  140.   
  141.   
  142.     }  
  143.     context.Response.Write(output);  
  144.     }  
  145.   
  146. public bool IsReusable  
  147. {  
  148.     get  
  149.     {  
  150.         return false;  
  151.     }  
  152. }  
  153.   
  154. public string GetMd5Hash(String input)  
  155. {  
  156.     if (input == null)  
  157.     {  
  158.         return null;  
  159.     }  
  160.   
  161.     MD5 md5Hash = MD5.Create();  
  162.   
  163.     // 将输入字符串转换为字节数组并计算哈希数据    
  164.     byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));  
  165.   
  166.     // 创建一个 Stringbuilder 来收集字节并创建字符串    
  167.     StringBuilder sBuilder = new StringBuilder();  
  168.   
  169.     // 循环遍历哈希数据的每一个字节并格式化为十六进制字符串    
  170.     for (int i = 0; i < data.Length; i++)  
  171.     {  
  172.         sBuilder.Append(data[i].ToString());  
  173.     }  
  174.   
  175.     // 返回十六进制字符串    
  176.     return sBuilder.ToString();  
  177. }  
  178. /// <summary>    
  179. /// 对象序列化成 XML String    
  180. /// </summary>    
  181. public static string XmlSerialize<T>(T obj)  
  182. {  
  183.     string xmlString = string.Empty;  
  184.     XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));  
  185.     using (MemoryStream ms = new MemoryStream())  
  186.     {  
  187.         xmlSerializer.Serialize(ms, obj);  
  188.         xmlString = Encoding.UTF8.GetString(ms.ToArray());  
  189.     }  
  190.     return xmlString;  
  191. }  
  192. /// <summary>  
  193. /// 从字符串里随机得到,规定个数的字符串.  
  194. /// </summary>  
  195. /// <param name="allChar"></param>  
  196. /// <param name="CodeCount"></param>  
  197. /// <returns></returns>  
  198. public static string GetRandomString(int CodeCount)  
  199. {  
  200.     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";  
  201.     string[] allCharArray = allChar.Split(',');  
  202.     string RandomCode = "";  
  203.     int temp = -1;  
  204.     Random rand = new Random();  
  205.     for (int i = 0; i < CodeCount; i++)  
  206.     {  
  207.         if (temp != -1)  
  208.         {  
  209.             rand = new Random(temp * i * ((int)DateTime.Now.Ticks));  
  210.         }  
  211.         int t = rand.Next(allCharArray.Length - 1);  
  212.         while (temp == t)  
  213.         {  
  214.             t = rand.Next(allCharArray.Length - 1);  
  215.         }  
  216.         temp = t;  
  217.         RandomCode += allCharArray[t];  
  218.     }  
  219.   
  220.     return RandomCode;  
  221. }  
  222.   
  223.   
  224. public static string GetWebClientIp()  
  225. {  
  226.     string userIP = "IP";  
  227.   
  228.     try  
  229.     {  
  230.         if (System.Web.HttpContext.Current == null  
  231.     || System.Web.HttpContext.Current.Request == null  
  232.     || System.Web.HttpContext.Current.Request.ServerVariables == null)  
  233.             return "";  
  234.   
  235.         string CustomerIP = "";  
  236.   
  237.         //CDN加速后取到的IP     
  238.         CustomerIP = System.Web.HttpContext.Current.Request.Headers["Cdn-Src-Ip"];  
  239.         if (!string.IsNullOrEmpty(CustomerIP))  
  240.         {  
  241.             return CustomerIP;  
  242.         }  
  243.   
  244.         CustomerIP = System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];  
  245.   
  246.   
  247.         if (!String.IsNullOrEmpty(CustomerIP))  
  248.             return CustomerIP;  
  249.   
  250.         if (System.Web.HttpContext.Current.Request.ServerVariables["HTTP_VIA"] != null)  
  251.         {  
  252.             CustomerIP = System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];  
  253.             if (CustomerIP == null)  
  254.                 CustomerIP = System.Web.HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];  
  255.         }  
  256.         else  
  257.         {  
  258.             CustomerIP = System.Web.HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];  
  259.   
  260.         }  
  261.   
  262.         if (string.Compare(CustomerIP, "unknown"true) == 0)  
  263.             return System.Web.HttpContext.Current.Request.UserHostAddress;  
  264.         return CustomerIP;  
  265.     }  
  266.     catch { }  
  267.   
  268.     return userIP;  
  269. }  
  270.   
  271.   
  272.   
  273.   
  274. private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)  
  275. {  
  276.     return true//总是接受     
  277. }  
  278.   
  279. public static HttpWebResponse CreatePostHttpResponse(string url, string datas, Encoding charset)  
  280. {  
  281.     HttpWebRequest request = null;  
  282.     //HTTPSQ请求  
  283.     ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);  
  284.     request = WebRequest.Create(url) as HttpWebRequest;  
  285.     request.ProtocolVersion = HttpVersion.Version10;  
  286.     request.Method = "POST";  
  287.     request.ContentType = "application/x-www-form-urlencoded";  
  288.   
  289.     //如果需要POST数据     
  290.     //if (!(parameters == null || parameters.Count == 0))  
  291.     //{  
  292.     StringBuilder buffer = new StringBuilder();  
  293.     //int i = 0;  
  294.     //foreach (string key in parameters.Keys)  
  295.     //{  
  296.     //    if (i > 0)  
  297.     //    {  
  298.     //        buffer.AppendFormat("&{0}={1}", key, parameters[key]);  
  299.     //    }  
  300.     //    else  
  301.     //    {  
  302.     //        buffer.AppendFormat("{0}={1}", key, parameters[key]);  
  303.     //    }  
  304.     //    i++;  
  305.     //}  
  306.     buffer.AppendFormat(datas);  
  307.     byte[] data = charset.GetBytes(buffer.ToString());  
  308.     using (Stream stream = request.GetRequestStream())  
  309.     {  
  310.         stream.Write(data, 0, data.Length);  
  311.     }  
  312.     //}  
  313.     return request.GetResponse() as HttpWebResponse;  
  314. }  
  315.   
  316.   
  317. public string GetSignString(Dictionary<stringstring> dic)  
  318. {  
  319.     string key = System.Web.Configuration.WebConfigurationManager.AppSettings["key"].ToString();//商户平台 API安全里面设置的KEY  32位长度  
  320.                                                                                                 //排序  
  321.     dic = dic.OrderBy(d => d.Key).ToDictionary(d => d.Key, d => d.Value);  
  322.     //连接字段  
  323.     var sign = dic.Aggregate("", (current, d) => current + (d.Key + "=" + d.Value + "&"));  
  324.     sign += "key=" + key;  
  325.     //MD5  
  326.     // sign = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(sign, "MD5").ToUpper();  
  327.     System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create();  
  328.     sign = BitConverter.ToString(md5.ComputeHash(Encoding.UTF8.GetBytes(sign))).Replace("-"null);  
  329.     return sign;  
  330. }  
  331.   
  332.   
  333. /// <summary>    
  334. /// 获取时间戳    
  335. /// </summary>    
  336. /// <returns></returns>    
  337. public static string GetTimeStamp()  
  338. {  
  339.     TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);  
  340.     return Convert.ToInt64(ts.TotalSeconds).ToString();  
  341. }  
  342.   
  343. }  



      微信返回信息接收后台页面notify_url.ashx

[csharp]  view plain  copy
  1. <%@ WebHandler Language="C#" Class="notify_url" %>  
  2.   
  3. using System;  
  4. using System.Web;  
  5. using System.Collections.Generic;  
  6. using System.Data;  
  7. using System.IO;  
  8. using System.Text;  
  9. using System.Xml;  
  10. using System.Net;  
  11. public class notify_url : IHttpHandler  
  12. {  
  13.     public string return_result = "";  
  14.     public void ProcessRequest(HttpContext context)  
  15.     {  
  16.         context.Response.ContentType = "text/plain";  
  17.         context.Response.Write("Hello World");  
  18.   
  19.   
  20.         String xmlData = getPostStr();//获取请求数据  
  21.         if (xmlData == "")  
  22.         {  
  23.   
  24.         }  
  25.         else  
  26.         {  
  27.             var dic = new Dictionary<stringstring>  
  28. {  
  29.     {"return_code""SUCCESS"},  
  30.     {"return_msg","OK"}  
  31.   
  32. };  
  33.             var sb = new StringBuilder();  
  34.             sb.Append("<xml>");  
  35.   
  36.   
  37.             foreach (var d in dic)  
  38.             {  
  39.                 sb.Append("<" + d.Key + ">" + d.Value + "</" + d.Key + ">");  
  40.             }  
  41.             sb.Append("</xml>");  
  42.   
  43.   
  44.   
  45.   
  46.   
  47.             //把数据重新返回给客户端  
  48.             DataSet ds = new DataSet();  
  49.             StringReader stram = new StringReader(xmlData);  
  50.             XmlTextReader datareader = new XmlTextReader(stram);  
  51.             ds.ReadXml(datareader);  
  52.             if (ds.Tables[0].Rows[0]["return_code"].ToString() == "SUCCESS")  
  53.             {  
  54.   
  55.   
  56.                 string wx_appid = "";//微信开放平台审核通过的应用APPID  
  57.                 string wx_mch_id = "";//微信支付分配的商户号  
  58.   
  59.                 string wx_nonce_str = "";//     随机字符串,不长于32位  
  60.                 string wx_sign = "";//签名,详见签名算法  
  61.                 string wx_result_code = "";//SUCCESS/FAIL  
  62.   
  63.                 string wx_return_code = "";  
  64.                 string wx_openid = "";//用户在商户appid下的唯一标识  
  65.                 string wx_is_subscribe = "";//用户是否关注公众账号,Y-关注,N-未关注,仅在公众账号类型支付有效  
  66.                 string wx_trade_type = "";//    APP  
  67.                 string wx_bank_type = "";//     银行类型,采用字符串类型的银行标识,银行类型见银行列表  
  68.                 string wx_fee_type = "";//  货币类型,符合ISO4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型  
  69.   
  70.   
  71.                 string wx_transaction_id = "";//微信支付订单号  
  72.                 string wx_out_trade_no = "";//商户系统的订单号,与请求一致。  
  73.                 string wx_time_end = "";//  支付完成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则  
  74.                 int wx_total_fee = -1;//    订单总金额,单位为分  
  75.                 int wx_cash_fee = -1;//现金支付金额订单现金支付金额,详见支付金额  
  76.  
  77.  
  78.                 #region  数据解析  
  79.                 //列 是否存在  
  80.                 string signstr = "";//需要前面的字符串  
  81.                                     //wx_appid  
  82.                 if (ds.Tables[0].Columns.Contains("appid"))  
  83.                 {  
  84.                     wx_appid = ds.Tables[0].Rows[0]["appid"].ToString();  
  85.                     if (!string.IsNullOrEmpty(wx_appid))  
  86.                     {  
  87.                         signstr += "appid=" + wx_appid;  
  88.                     }  
  89.                 }  
  90.   
  91.                 //wx_bank_type  
  92.                 if (ds.Tables[0].Columns.Contains("bank_type"))  
  93.                 {  
  94.                     wx_bank_type = ds.Tables[0].Rows[0]["bank_type"].ToString();  
  95.                     if (!string.IsNullOrEmpty(wx_bank_type))  
  96.                     {  
  97.                         signstr += "&bank_type=" + wx_bank_type;  
  98.                     }  
  99.                 }  
  100.                 //wx_cash_fee  
  101.                 if (ds.Tables[0].Columns.Contains("cash_fee"))  
  102.                 {  
  103.                     wx_cash_fee = Convert.ToInt32(ds.Tables[0].Rows[0]["cash_fee"].ToString());  
  104.   
  105.                     signstr += "&cash_fee=" + wx_cash_fee;  
  106.                 }  
  107.   
  108.                 //wx_fee_type  
  109.                 if (ds.Tables[0].Columns.Contains("fee_type"))  
  110.                 {  
  111.                     wx_fee_type = ds.Tables[0].Rows[0]["fee_type"].ToString();  
  112.                     if (!string.IsNullOrEmpty(wx_fee_type))  
  113.                     {  
  114.                         signstr += "&fee_type=" + wx_fee_type;  
  115.                     }  
  116.                 }  
  117.   
  118.                 //wx_is_subscribe  
  119.                 if (ds.Tables[0].Columns.Contains("is_subscribe"))  
  120.                 {  
  121.                     wx_is_subscribe = ds.Tables[0].Rows[0]["is_subscribe"].ToString();  
  122.                     if (!string.IsNullOrEmpty(wx_is_subscribe))  
  123.                     {  
  124.                         signstr += "&is_subscribe=" + wx_is_subscribe;  
  125.                     }  
  126.                 }  
  127.   
  128.                 //wx_mch_id  
  129.                 if (ds.Tables[0].Columns.Contains("mch_id"))  
  130.                 {  
  131.                     wx_mch_id = ds.Tables[0].Rows[0]["mch_id"].ToString();  
  132.                     if (!string.IsNullOrEmpty(wx_mch_id))  
  133.                     {  
  134.                         signstr += "&mch_id=" + wx_mch_id;  
  135.                     }  
  136.                 }  
  137.   
  138.                 //wx_nonce_str  
  139.                 if (ds.Tables[0].Columns.Contains("nonce_str"))  
  140.                 {  
  141.                     wx_nonce_str = ds.Tables[0].Rows[0]["nonce_str"].ToString();  
  142.                     if (!string.IsNullOrEmpty(wx_nonce_str))  
  143.                     {  
  144.                         signstr += "&nonce_str=" + wx_nonce_str;  
  145.                     }  
  146.                 }  
  147.   
  148.                 //wx_openid  
  149.                 if (ds.Tables[0].Columns.Contains("openid"))  
  150.                 {  
  151.                     wx_openid = ds.Tables[0].Rows[0]["openid"].ToString();  
  152.                     if (!string.IsNullOrEmpty(wx_openid))  
  153.                     {  
  154.                         signstr += "&openid=" + wx_openid;  
  155.                     }  
  156.                 }  
  157.   
  158.                 //wx_out_trade_no  
  159.                 if (ds.Tables[0].Columns.Contains("out_trade_no"))  
  160.                 {  
  161.                     wx_out_trade_no = ds.Tables[0].Rows[0]["out_trade_no"].ToString();  
  162.                     if (!string.IsNullOrEmpty(wx_out_trade_no))  
  163.                     {  
  164.                         signstr += "&out_trade_no=" + wx_out_trade_no;  
  165.                     }  
  166.                 }  
  167.   
  168.                 //wx_result_code   
  169.                 if (ds.Tables[0].Columns.Contains("result_code"))  
  170.                 {  
  171.                     wx_result_code = ds.Tables[0].Rows[0]["result_code"].ToString();  
  172.                     if (!string.IsNullOrEmpty(wx_result_code))  
  173.                     {  
  174.                         signstr += "&result_code=" + wx_result_code;  
  175.                     }  
  176.                 }  
  177.   
  178.                 //wx_result_code   
  179.                 if (ds.Tables[0].Columns.Contains("return_code"))  
  180.                 {  
  181.                     wx_return_code = ds.Tables[0].Rows[0]["return_code"].ToString();  
  182.                     if (!string.IsNullOrEmpty(wx_return_code))  
  183.                     {  
  184.                         signstr += "&return_code=" + wx_return_code;  
  185.                     }  
  186.                 }  
  187.   
  188.                 //wx_sign   
  189.                 if (ds.Tables[0].Columns.Contains("sign"))  
  190.                 {  
  191.                     wx_sign = ds.Tables[0].Rows[0]["sign"].ToString();  
  192.                     //if (!string.IsNullOrEmpty(wx_sign))  
  193.                     //{  
  194.                     //    signstr += "&sign=" + wx_sign;  
  195.                     //}  
  196.                 }  
  197.   
  198.                 //wx_time_end  
  199.                 if (ds.Tables[0].Columns.Contains("time_end"))  
  200.                 {  
  201.                     wx_time_end = ds.Tables[0].Rows[0]["time_end"].ToString();  
  202.                     if (!string.IsNullOrEmpty(wx_time_end))  
  203.                     {  
  204.                         signstr += "&time_end=" + wx_time_end;  
  205.                     }  
  206.                 }  
  207.   
  208.                 //wx_total_fee  
  209.                 if (ds.Tables[0].Columns.Contains("total_fee"))  
  210.                 {  
  211.                     wx_total_fee = Convert.ToInt32(ds.Tables[0].Rows[0]["total_fee"].ToString());  
  212.   
  213.                     signstr += "&total_fee=" + wx_total_fee;  
  214.                 }  
  215.   
  216.                 //wx_trade_type  
  217.                 if (ds.Tables[0].Columns.Contains("trade_type"))  
  218.                 {  
  219.                     wx_trade_type = ds.Tables[0].Rows[0]["trade_type"].ToString();  
  220.                     if (!string.IsNullOrEmpty(wx_trade_type))  
  221.                     {  
  222.                         signstr += "&trade_type=" + wx_trade_type;  
  223.                     }  
  224.                 }  
  225.   
  226.                 //wx_transaction_id  
  227.                 if (ds.Tables[0].Columns.Contains("transaction_id"))  
  228.                 {  
  229.                     wx_transaction_id = ds.Tables[0].Rows[0]["transaction_id"].ToString();  
  230.                     if (!string.IsNullOrEmpty(wx_transaction_id))  
  231.                     {  
  232.                         signstr += "&transaction_id=" + wx_transaction_id;  
  233.                     }  
  234.                 }  
  235.  
  236.                 #endregion  
  237.   
  238.                 //追加key 密钥  
  239.                 signstr += "&key=" + System.Web.Configuration.WebConfigurationManager.AppSettings["key"].ToString();  
  240.                 //签名正确  
  241.                 string orderStrwhere = "ordernumber='" + wx_out_trade_no + "'";  
  242.   
  243.   
  244.   
  245.                 if (wx_sign == System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(signstr, "MD5").ToUpper())  
  246.                 {  
  247.                     //签名正确   处理订单操作逻辑  
  248.   
  249.   
  250.                 }  
  251.                 else  
  252.                 {  
  253.                     //追加备注信息  
  254.   
  255.                 }  
  256.   
  257.             }  
  258.             else  
  259.             {  
  260.                 // 返回信息,如非空,为错误原因  签名失败 参数格式校验错误  
  261.                 string return_msg = ds.Tables[0].Rows[0]["return_msg"].ToString();  
  262.   
  263.             }  
  264.   
  265.   
  266.             return_result = sb.ToString();  
  267.         }  
  268.     }  
  269.   
  270.   
  271.     public bool IsReusable  
  272.     {  
  273.         get  
  274.         {  
  275.             return false;  
  276.         }  
  277.     }  
  278.   
  279.     //获得Post过来的数据  
  280.     public string getPostStr()  
  281.     {  
  282.         Int32 intLen = Convert.ToInt32(System.Web.HttpContext.Current.Request.InputStream.Length);  
  283.         byte[] b = new byte[intLen];  
  284.         System.Web.HttpContext.Current.Request.InputStream.Read(b, 0, intLen);  
  285.         return System.Text.Encoding.UTF8.GetString(b);  
  286.     }  
  287. }  

退款:

[csharp]  view plain  copy
  1. <%@ WebHandler Language="C#" Class="jiesuan" %>  
  2.   
  3. using System;  
  4. using System.Web;  
  5. using System.Net;  
  6. using System.IO;  
  7. using System.Configuration;  
  8. using Maticsoft.Model;  
  9. using Maticsoft.BLL;  
  10. using System.Security.Cryptography;  
  11. using System.Text;  
  12. using System.Xml.Serialization;  
  13. using System.Xml;  
  14. using System.Collections.Generic;  
  15. using System.Data;  
  16. using System.Net.Security;  
  17. using System.Security.Cryptography.X509Certificates;  
  18. using System.Linq;  
  19. using Newtonsoft.Json;  
  20.   
  21. public class jiesuan : IHttpHandler  
  22. {  
  23.   
  24.     public void ProcessRequest(HttpContext context)  
  25.     {  
  26.         context.Response.ContentType = "text/plain";  
  27.         // string openid = context.Request.Params["openid"];  
  28.         // string ordertime = context.Request.Params["ordertime"];  
  29.         string orderid = context.Request.Params["order_id"];  
  30.         string appid = ConfigurationManager.AppSettings["appid"];  
  31.         string secret = ConfigurationManager.AppSettings["secret"];  
  32.         string key = ConfigurationManager.AppSettings["key"];  
  33.         string mch_id = ConfigurationManager.AppSettings["mch_id"];  
  34.         string ip = ConfigurationManager.AppSettings["ip"];  
  35.         string PayResulturl = ConfigurationManager.AppSettings["PayResulturl"];  
  36.         //string roomid = context.Request.Params["roomid"];  
  37.         string aa = "私密自助棋牌室-退款";////商品描述交易字段格式根据不同的应用场景按照以下格式:APP——需传入应用市场上的APP名字-实际商品名称,天天爱消除-游戏充值。  
  38.   
  39.         string strcode = aa;  
  40.         byte[] buffer = Encoding.UTF8.GetBytes(strcode);  
  41.         string body = Encoding.UTF8.GetString(buffer, 0, buffer.Length);  
  42.         DateTime timestart;  
  43.         int totalhour;  
  44.         float totalfee;  
  45.         float pay_price;  
  46.         float refund_fee;  
  47.         string out_refund_no;  
  48.         int roomid;  
  49.         string openid;  
  50.         //string totalfee = context.Request.Params["totalfee"];  
  51.         string output = "";  
  52.         string signapp;  
  53.         DataSet orderhistory;  
  54.         if ((context.Request.Params["order_id"] != null) && (context.Request.Params["order_id"] != ""))  
  55.         {  
  56.             Maticsoft.BLL.order_history oh = new Maticsoft.BLL.order_history();  
  57.             orderhistory = oh.GetList(" order_id=" + orderid + "");  
  58.             pay_price = Convert.ToSingle(orderhistory.Tables[0].Rows[0]["pay_price"]);  
  59.             roomid = Convert.ToInt32(orderhistory.Tables[0].Rows[0]["room_id"]);  
  60.             openid = orderhistory.Tables[0].Rows[0]["openid"].ToString();  
  61.             System.Random Random = new System.Random();  
  62.   
  63.   
  64.             timestart = Convert.ToDateTime(orderhistory.Tables[0].Rows[0]["order_timestart"]);//订单开始时间  
  65.   
  66.             TimeSpan ts = DateTime.Now - timestart; //时间差的绝对值    
  67.             totalhour = Convert.ToInt32(ts.Hours);//间隔小时数  
  68.   
  69.             totalfee = totalhour * Convert.ToSingle(orderhistory.Tables[0].Rows[0]["price"]);  
  70.             out_refund_no = roomid + DateTime.Now.ToString("yyyyMMddHHmmssfff") + Random.Next(999).ToString();  
  71.             refund_fee = totalfee - pay_price;  
  72.             var dic = new Dictionary<stringstring>  
  73. {  
  74.     {"appid", appid},  
  75.     {"mch_id", mch_id},  
  76.     {"nonce_str", GetRandomString(20)/*Random.Next().ToString()*/},  
  77.      {"op_user_id",mch_id},  
  78.       {"out_refund_no",out_refund_no},//商户退款号  
  79.     {"out_trade_no",orderhistory.Tables[0].Rows[0]["out_trade_no"].ToString()},//商户自己的订单号码  
  80.     {"refund_fee",/*refund_fee.ToString()*/"1"},//退款金额  
  81.     {"total_fee",orderhistory.Tables[0].Rows[0]["pay_price"].ToString()},//订单金额  
  82.     
  83.   
  84. };  
  85.   
  86.             //加入签名  
  87.             dic.Add("sign", GetSignString(dic));  
  88.   
  89.             var sb = new StringBuilder();  
  90.             sb.Append("<xml>");  
  91.   
  92.   
  93.             foreach (var d in dic)  
  94.             {  
  95.                 sb.Append("<" + d.Key + ">" + d.Value + "</" + d.Key + ">");  
  96.             }  
  97.             sb.Append("</xml>");  
  98.             var xml = new XmlDocument();  
  99.             //  xml.LoadXml(GetPostString("https://api.mch.weixin.qq.com/pay/unifiedorder", sb.ToString()));  
  100.             CookieCollection coo = new CookieCollection();  
  101.             Encoding en = Encoding.GetEncoding("UTF-8");  
  102.   
  103.             HttpWebResponse response = CreatePostHttpResponse("https://api.mch.weixin.qq.com/secapi/pay/refund", sb.ToString(), en);  
  104.             //打印返回值  
  105.             Stream stream = response.GetResponseStream();   //获取响应的字符串流  
  106.             StreamReader sr = new StreamReader(stream); //创建一个stream读取流  
  107.             string html = sr.ReadToEnd();   //从头读到尾,放到字符串html  
  108.                                             //Console.WriteLine(html);  
  109.             xml.LoadXml(html);  
  110.             //对请求返回值 进行处理  
  111.   
  112.             var root = xml.DocumentElement;  
  113.   
  114.             DataSet ds = new DataSet();  
  115.             StringReader stram = new StringReader(html);  
  116.             XmlTextReader reader = new XmlTextReader(stram);  
  117.             ds.ReadXml(reader);  
  118.             string return_code = ds.Tables[0].Rows[0]["return_code"].ToString();  
  119.             string return_mesage = ds.Tables[0].Rows[0]["return_msg"].ToString();  
  120.             if (return_code.ToUpper() == "SUCCESS")  
  121.             {  
  122.                 //通信成功  
  123.                 string result_code = ds.Tables[0].Rows[0]["result_code"].ToString();//业务结果  
  124.                 if (result_code.ToUpper() == "SUCCESS")  
  125.                 {  
  126.                     if ((context.Request.Params["order_id"] != null) && (context.Request.Params["order_id"] != ""))  
  127.                     {  
  128.                         //更新订单信息  
  129.                         Maticsoft.Model.pokerrooms model = new Maticsoft.Model.pokerrooms();  
  130.   
  131.                         Maticsoft.Model.order_history oh1 = new Maticsoft.Model.order_history();  
  132.                         Maticsoft.BLL.pokerrooms b = new Maticsoft.BLL.pokerrooms();  
  133.   
  134.                         Maticsoft.BLL.order_history bll = new Maticsoft.BLL.order_history();  
  135.                         model = b.GetModel(roomid);  
  136.                         oh1 = bll.GetModel(Convert.ToInt32(orderid));  
  137.   
  138.                         oh1.order_timeend = DateTime.Now;  
  139.                         oh1.out_refund_no = out_refund_no;  
  140.                         oh1.refund_fee = Convert.ToDecimal(refund_fee);  
  141.   
  142.                         bll.Update(oh1);  
  143.   
  144.                         model.attribute1 = "0";//0空闲  1 使用中  
  145.                         model.room_id =Convert.ToInt32(oh1.room_id);  
  146.   
  147.                         b.Update(model);//更新棋牌室使用状态  
  148.                         var res = new Dictionary<stringstring>  
  149. {  
  150.     {"out_refund_no", out_refund_no},  
  151.     {"return_mesage", return_mesage},  
  152.     {"return_code", return_code},  
  153.     {"refund_fee",refund_fee.ToString() },  
  154.     {"order_timeend", oh1.order_timeend.ToString() },  
  155.     {"order_id", oh1.order_id.ToString() }  
  156.   
  157. };  
  158.                         signapp = JsonConvert.SerializeObject(res);  
  159.                         context.Response.Write(signapp);  
  160.                     }  
  161.   
  162.                 }  
  163.             }  
  164.   
  165.   
  166.   
  167.   
  168.         }  
  169.       //  context.Response.Write(output);  
  170.     }  
  171.   
  172.     public bool IsReusable  
  173.     {  
  174.         get  
  175.         {  
  176.             return false;  
  177.         }  
  178.     }  
  179.   
  180.     public string GetMd5Hash(String input)  
  181.     {  
  182.         if (input == null)  
  183.         {  
  184.             return null;  
  185.         }  
  186.   
  187.         MD5 md5Hash = MD5.Create();  
  188.   
  189.         // 将输入字符串转换为字节数组并计算哈希数据    
  190.         byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));  
  191.   
  192.         // 创建一个 Stringbuilder 来收集字节并创建字符串    
  193.         StringBuilder sBuilder = new StringBuilder();  
  194.   
  195.         // 循环遍历哈希数据的每一个字节并格式化为十六进制字符串    
  196.         for (int i = 0; i < data.Length; i++)  
  197.         {  
  198.             sBuilder.Append(data[i].ToString());  
  199.         }  
  200.   
  201.         // 返回十六进制字符串    
  202.         return sBuilder.ToString();  
  203.     }  
  204.     /// <summary>    
  205.     /// 对象序列化成 XML String    
  206.     /// </summary>    
  207.     public static string XmlSerialize<T>(T obj)  
  208.     {  
  209.         string xmlString = string.Empty;  
  210.         XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));  
  211.         using (MemoryStream ms = new MemoryStream())  
  212.         {  
  213.             xmlSerializer.Serialize(ms, obj);  
  214.             xmlString = Encoding.UTF8.GetString(ms.ToArray());  
  215.         }  
  216.         return xmlString;  
  217.     }  
  218.     /// <summary>  
  219.     /// 从字符串里随机得到,规定个数的字符串.  
  220.     /// </summary>  
  221.     /// <param name="allChar"></param>  
  222.     /// <param name="CodeCount"></param>  
  223.     /// <returns></returns>  
  224.     public static string GetRandomString(int CodeCount)  
  225.     {  
  226.         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";  
  227.         string[] allCharArray = allChar.Split(',');  
  228.         string RandomCode = "";  
  229.         int temp = -1;  
  230.         Random rand = new Random();  
  231.         for (int i = 0; i < CodeCount; i++)  
  232.         {  
  233.             if (temp != -1)  
  234.             {  
  235.                 rand = new Random(temp * i * ((int)DateTime.Now.Ticks));  
  236.             }  
  237.             int t = rand.Next(allCharArray.Length - 1);  
  238.             while (temp == t)  
  239.             {  
  240.                 t = rand.Next(allCharArray.Length - 1);  
  241.             }  
  242.             temp = t;  
  243.             RandomCode += allCharArray[t];  
  244.         }  
  245.   
  246.         return RandomCode;  
  247.     }  
  248.   
  249.   
  250.     public static string GetWebClientIp()  
  251.     {  
  252.         string userIP = "IP";  
  253.   
  254.         try  
  255.         {  
  256.             if (System.Web.HttpContext.Current == null  
  257.         || System.Web.HttpContext.Current.Request == null  
  258.         || System.Web.HttpContext.Current.Request.ServerVariables == null)  
  259.                 return "";  
  260.   
  261.             string CustomerIP = "";  
  262.   
  263.             //CDN加速后取到的IP     
  264.             CustomerIP = System.Web.HttpContext.Current.Request.Headers["Cdn-Src-Ip"];  
  265.             if (!string.IsNullOrEmpty(CustomerIP))  
  266.             {  
  267.                 return CustomerIP;  
  268.             }  
  269.   
  270.             CustomerIP = System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];  
  271.   
  272.   
  273.             if (!String.IsNullOrEmpty(CustomerIP))  
  274.                 return CustomerIP;  
  275.   
  276.             if (System.Web.HttpContext.Current.Request.ServerVariables["HTTP_VIA"] != null)  
  277.             {  
  278.                 CustomerIP = System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];  
  279.                 if (CustomerIP == null)  
  280.                     CustomerIP = System.Web.HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];  
  281.             }  
  282.             else  
  283.             {  
  284.                 CustomerIP = System.Web.HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];  
  285.   
  286.             }  
  287.   
  288.             if (string.Compare(CustomerIP, "unknown"true) == 0)  
  289.                 return System.Web.HttpContext.Current.Request.UserHostAddress;  
  290.             return CustomerIP;  
  291.         }  
  292.         catch { }  
  293.   
  294.         return userIP;  
  295.     }  
  296.   
  297.   
  298.   
  299.   
  300.     private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)  
  301.     {  
  302.         return true//总是接受     
  303.     }  
  304.   
  305.     public static HttpWebResponse CreatePostHttpResponse(string url, string datas, Encoding charset)  
  306.     {  
  307.        // string cert = @"C:\apiclient_cert.p12";  
  308.        string cert =System.Web.HttpContext.Current.Server.MapPath("/apiclient_cert.p12");  //证书已上传到网站根目录,注意安全性问题  
  309.         string password = ConfigurationManager.AppSettings["mch_id"];  
  310.        
  311.      //   X509Certificate cer = new X509Certificate(cert, password);//经过测试,这个发布到IIS后,发起微信退款时会引起<span style="color:rgb(255,0,0);font-family:Verdana, Geneva, Arial, Helvetica, sans-serif;font-size:13px;">"基础连接已经关闭: 连接被意外关闭"</span>  
  312.           
  313.   
  314.             X509Certificate2 cer = new X509Certificate2(cert, password, X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.MachineKeySet);  
  315.   
  316.    
  317.   
  318.         HttpWebRequest request = null;  
  319.         //HTTPSQ请求  
  320.         ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);  
  321.         request = WebRequest.Create(url) as HttpWebRequest;  
  322.   
  323.         request.ProtocolVersion = HttpVersion.Version10;  
  324.         request.ClientCertificates.Add(cer);//add by sui 20170505  
  325.         request.Method = "POST";  
  326.         request.ContentType = "application/x-www-form-urlencoded";  
  327.   
  328.   
  329.         //如果需要POST数据     
  330.         //if (!(parameters == null || parameters.Count == 0))  
  331.         //{  
  332.         StringBuilder buffer = new StringBuilder();  
  333.         //int i = 0;  
  334.         //foreach (string key in parameters.Keys)  
  335.         //{  
  336.         //    if (i > 0)  
  337.         //    {  
  338.         //        buffer.AppendFormat("&{0}={1}", key, parameters[key]);  
  339.         //    }  
  340.         //    else  
  341.         //    {  
  342.         //        buffer.AppendFormat("{0}={1}", key, parameters[key]);  
  343.         //    }  
  344.         //    i++;  
  345.         //}  
  346.         buffer.AppendFormat(datas);  
  347.         byte[] data = charset.GetBytes(buffer.ToString());  
  348.         using (Stream stream = request.GetRequestStream())  
  349.         {  
  350.             stream.Write(data, 0, data.Length);  
  351.         }  
  352.         //}  
  353.   
  354.         return request.GetResponse() as HttpWebResponse;  
  355.   
  356.   
  357.     }  
  358.   
  359.   
  360.     public string GetSignString(Dictionary<stringstring> dic)  
  361.     {  
  362.         string key = System.Web.Configuration.WebConfigurationManager.AppSettings["key"].ToString();//商户平台 API安全里面设置的KEY  32位长度  
  363.                                                                                                     //排序  
  364.         dic = dic.OrderBy(d => d.Key).ToDictionary(d => d.Key, d => d.Value);  
  365.         //连接字段  
  366.         var sign = dic.Aggregate("", (current, d) => current + (d.Key + "=" + d.Value + "&"));  
  367.         sign += "key=" + key;  
  368.         //MD5  
  369.         // sign = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(sign, "MD5").ToUpper();  
  370.         System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create();  
  371.         sign = BitConverter.ToString(md5.ComputeHash(Encoding.UTF8.GetBytes(sign))).Replace("-"null);  
  372.         return sign;  
  373.     }  
  374.   
  375.   
  376.     /// <summary>    
  377.     /// 获取时间戳    
  378.     /// </summary>    
  379.     /// <returns></returns>    
  380.     public static string GetTimeStamp()  
  381.     {  
  382.         TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);  
  383.         return Convert.ToInt64(ts.TotalSeconds).ToString();  
  384.     }  
  385.   
  386. }  

猜你喜欢

转载自blog.csdn.net/lishimin1012/article/details/80243617