C#版微信公衆號支付|微信H5支付|微信掃碼支付問題彙總及解決方案總結

最近負責的一些項目開發,都用到了微信支付(微信公衆號支付、微信H5支付、微信掃碼支付)。在開發的過程當中,在調試支付的過程當中,或多或少都遇到了一些問題,今天總結下,分享,留存。代碼在文章結尾處,有須要的同窗能夠下載看下。php

先說注意的第一點,全部支付的第一步都是請求統一下單,統一下單,統一下單,請求URL地址:https://api.mch.weixin.qq.com/pay/unifiedorder。node

再說一個微信官方提供的一個很重要的工具,微信支付接口簽名校驗工具(網址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=20_1),此工具旨在幫助開發者檢測調用【微信支付接口API】時發送的請求參數中生成的簽名是否正確,提交相關信息後可得到簽名校驗結果。特別實用!特別實用!特別實用!簽名只要正確了,一切就OK了!web

 

第一部分 微信公衆號支付算法

 

微信公衆號支付須要配置的參數有:APPID(微信公衆號開發者ID)、APPSECRET(微信公衆號開發者密碼)、MCHID(商戶ID)、KEY(商戶密鑰)。json

 

微信公衆號支付應用的場景是在微信內部的H5環境中使用的支付方式。由於要經過網頁受權獲取用戶的OpenId,因此必需要配置網頁受權域名。同時要配置JS接口安全域名。api

JsApiConfig.cs數組

 1 using System.Web;
 2 using System.Text;
 3 using System.IO;
 4 using System.Net;
 5 using System;
 6 using System.Xml;
 7 using System.Collections.Generic;
 8 using Gwbnsh.Common;
 9 
10 namespace Gwbnsh.API.Payment.wxpay
11 {
12     public class JsApiConfig
13     {
14         #region 字段
15         private string partner = string.Empty;
16         private string key = string.Empty;
17         private string appid = string.Empty;
18         private string appsecret = string.Empty;
19         private string redirect_url = string.Empty;
20         private string notify_url = string.Empty;
21         #endregion
22 
23         public JsApiConfig(int site_payment_id)
24         {
25             Model.site_payment model = new BLL.site_payment().GetModel(site_payment_id); //站點支付方式
26             if (model != null)
27             {
28                 Model.payment payModel = new BLL.payment().GetModel(model.payment_id); //支付平臺
29                 Model.sites siteModel = new BLL.sites().GetModel(model.site_id); //站點配置
30                 Model.sysconfig sysConfig = new BLL.sysconfig().loadConfig(); //系統配置
31 
32                 partner = model.key1; //商戶號(必須配置)
33                 key = model.key2; //商戶支付密鑰,參考開戶郵件設置(必須配置)
34                 appid = model.key3; //綁定支付的APPID(必須配置)
35                 appsecret = model.key4; //公衆賬號secert(僅JSAPI支付的時候須要配置)
36 
37                 //獲取用戶的OPENID回調地址及登陸後的回調地址
38                 redirect_url = "http://m.gwbnsh.net.cn/hd/SellPhone" + payModel.return_url;
39                 notify_url = "http://m.gwbnsh.net.cn/hd/SellPhone" + payModel.notify_url;
40                 }
41             }
42         }
43 
44         #region 屬性
45         /// <summary>
46         /// 商戶號(必須配置)
47         /// </summary>
48         public string Partner
49         {
50             get { return partner; }
51             set { partner = value; }
52         }
53 
54         /// <summary>
55         /// 獲取或設交易安全校驗碼
56         /// </summary>
57         public string Key
58         {
59             get { return key; }
60             set { key = value; }
61         }
62 
63         /// <summary>
64         /// 綁定支付的APPID(必須配置)
65         /// </summary>
66         public string AppId
67         {
68             get { return appid; }
69             set { appid = value; }
70         }
71 
72         /// <summary>
73         /// 公衆賬號secert(僅JSAPI支付的時候須要配置)
74         /// </summary>
75         public string AppSecret
76         {
77             get { return appsecret; }
78             set { appsecret = value; }
79         }
80 
81         /// <summary>
82         /// 獲取用戶的OPENID回調地址
83         /// </summary>
84         public string Redirect_url
85         {
86             get { return redirect_url; }
87         }
88 
89         /// <summary>
90         /// 獲取服務器異步通知頁面路徑
91         /// </summary>
92         public string Notify_url
93         {
94             get { return notify_url; }
95         }
96 
97         #endregion
98     }
99 }
JsApiConfig.cs

JsApiPay.cs瀏覽器

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Web;
  4 using System.Net;
  5 using System.IO;
  6 using System.Text;
  7 using Gwbnsh.Common;
  8 
  9 namespace Gwbnsh.API.Payment.wxpay
 10 {
 11     public class JsApiPay
 12     {
 13         /**
 14         * 
 15         * 測速上報
 16         * @param string interface_url 接口URL
 17         * @param int timeCost 接口耗時
 18         * @param WxPayData inputObj參數數組
 19         */
 20         public static void ReportCostTime(int paymentId, string interface_url, int timeCost, WxPayData inputObj)
 21         {
 22             //若是僅失敗上報
 23             if (inputObj.IsSet("return_code") && inputObj.GetValue("return_code").ToString() == "SUCCESS" &&
 24              inputObj.IsSet("result_code") && inputObj.GetValue("result_code").ToString() == "SUCCESS")
 25             {
 26                 return;
 27             }
 28 
 29             //上報邏輯
 30             WxPayData data = new WxPayData();
 31             data.SetValue("interface_url", interface_url);
 32             data.SetValue("execute_time_", timeCost);
 33             //返回狀態碼
 34             if (inputObj.IsSet("return_code"))
 35             {
 36                 data.SetValue("return_code", inputObj.GetValue("return_code"));
 37             }
 38             //返回信息
 39             if (inputObj.IsSet("return_msg"))
 40             {
 41                 data.SetValue("return_msg", inputObj.GetValue("return_msg"));
 42             }
 43             //業務結果
 44             if (inputObj.IsSet("result_code"))
 45             {
 46                 data.SetValue("result_code", inputObj.GetValue("result_code"));
 47             }
 48             //錯誤代碼
 49             if (inputObj.IsSet("err_code"))
 50             {
 51                 data.SetValue("err_code", inputObj.GetValue("err_code"));
 52             }
 53             //錯誤代碼描述
 54             if (inputObj.IsSet("err_code_des"))
 55             {
 56                 data.SetValue("err_code_des", inputObj.GetValue("err_code_des"));
 57             }
 58             //商戶訂單號
 59             if (inputObj.IsSet("out_trade_no"))
 60             {
 61                 data.SetValue("out_trade_no", inputObj.GetValue("out_trade_no"));
 62             }
 63             //設備號
 64             if (inputObj.IsSet("device_info"))
 65             {
 66                 data.SetValue("device_info", inputObj.GetValue("device_info"));
 67             }
 68 
 69             try
 70             {
 71                 Report(paymentId, data);
 72             }
 73             catch (WxPayException ex)
 74             {
 75                 //不作任何處理
 76             }
 77         }
 78 
 79         /**
 80         * 
 81         * 測速上報接口實現
 82         * @param WxPayData inputObj 提交給測速上報接口的參數
 83         * @param int timeOut 測速上報接口超時時間
 84         * @throws WxPayException
 85         * @return 成功時返回測速上報接口返回的結果,其餘拋異常
 86         */
 87         public static WxPayData Report(int paymentId, WxPayData inputObj, int timeOut = 1)
 88         {
 89             JsApiConfig jsApiConfig = new JsApiConfig(paymentId);
 90             string url = "https://api.mch.weixin.qq.com/payitil/report";
 91             //檢測必填參數
 92             if (!inputObj.IsSet("interface_url"))
 93             {
 94                 throw new WxPayException("接口URL,缺乏必填參數interface_url!");
 95             }
 96             if (!inputObj.IsSet("return_code"))
 97             {
 98                 throw new WxPayException("返回狀態碼,缺乏必填參數return_code!");
 99             }
100             if (!inputObj.IsSet("result_code"))
101             {
102                 throw new WxPayException("業務結果,缺乏必填參數result_code!");
103             }
104             if (!inputObj.IsSet("user_ip"))
105             {
106                 throw new WxPayException("訪問接口IP,缺乏必填參數user_ip!");
107             }
108             if (!inputObj.IsSet("execute_time_"))
109             {
110                 throw new WxPayException("接口耗時,缺乏必填參數execute_time_!");
111             }
112 
113             inputObj.SetValue("appid", jsApiConfig.AppId);//公衆帳號ID
114             inputObj.SetValue("mch_id", jsApiConfig.Partner);//商戶號
115             inputObj.SetValue("user_ip", DTRequest.GetIP());//終端ip
116             inputObj.SetValue("time", DateTime.Now.ToString("yyyyMMddHHmmss"));//商戶上報時間     
117             inputObj.SetValue("nonce_str", GenerateNonceStr());//隨機字符串
118             inputObj.SetValue("sign", inputObj.MakeSign(jsApiConfig.Key));//簽名
119             string xml = inputObj.ToXml();
120 
121             string response = HttpService.Post(xml, url, false, timeOut);
122 
123             WxPayData result = new WxPayData();
124             result.FromXml(response, jsApiConfig.Key);
125             return result;
126         }
127 
128         /**
129         * 生成時間戳,標準北京時間,時區爲東八區,自1970年1月1日 0點0分0秒以來的秒數
130          * @return 時間戳
131         */
132         public static string GenerateTimeStamp()
133         {
134             TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
135             return Convert.ToInt64(ts.TotalSeconds).ToString();
136         }
137 
138         /**
139         * 生成隨機串,隨機串包含字母或數字
140         * @return 隨機串
141         */
142         public static string GenerateNonceStr()
143         {
144             return Guid.NewGuid().ToString().Replace("-", "");
145         }
146 
147         /// <summary>
148         /// 接收從微信支付後臺發送過來的數據暫不驗證簽名
149         /// </summary>
150         /// <returns>微信支付後臺返回的數據</returns>
151         public static WxPayData GetNotifyData()
152         {
153             //接收從微信後臺POST過來的數據
154             System.IO.Stream s = HttpContext.Current.Request.InputStream;
155             int count = 0;
156             byte[] buffer = new byte[1024];
157             StringBuilder builder = new StringBuilder();
158             while ((count = s.Read(buffer, 0, 1024)) > 0)
159             {
160                 builder.Append(Encoding.UTF8.GetString(buffer, 0, count));
161             }
162             s.Flush();
163             s.Close();
164             s.Dispose();
165 
166             //轉換數據格式並驗證簽名
167             WxPayData data = new WxPayData();
168             try
169             {
170                 data.FromXml(builder.ToString());
171             }
172             catch (WxPayException ex)
173             {
174                 //如有錯誤,則當即返回結果給微信支付後臺
175                 WxPayData res = new WxPayData();
176                 res.SetValue("return_code", "FAIL");
177                 res.SetValue("return_msg", ex.Message);
178                 HttpContext.Current.Response.Write(res.ToXml());
179                 HttpContext.Current.Response.End();
180             }
181 
182             return data;
183         }
184 
185         /**
186         *    
187         * 查詢訂單
188         * @param WxPayData inputObj 提交給查詢訂單API的參數
189         * @param int timeOut 超時時間
190         * @throws WxPayException
191         * @return 成功時返回訂單查詢結果,其餘拋異常
192         */
193         public static WxPayData OrderQuery(int paymentId, WxPayData inputObj, int timeOut = 6)
194         {
195             string sendUrl = "https://api.mch.weixin.qq.com/pay/orderquery";
196             //檢測必填參數
197             if (!inputObj.IsSet("out_trade_no") && !inputObj.IsSet("transaction_id"))
198             {
199                 throw new WxPayException("訂單查詢接口中,out_trade_no、transaction_id至少填一個!");
200             }
201             JsApiConfig jsApiConfig = new JsApiConfig(paymentId);
202             inputObj.SetValue("appid", jsApiConfig.AppId);//公衆帳號ID
203             inputObj.SetValue("mch_id", jsApiConfig.Partner);//商戶號
204             inputObj.SetValue("nonce_str", GenerateNonceStr());//隨機字符串
205             inputObj.SetValue("sign", inputObj.MakeSign(jsApiConfig.Key));//簽名
206             string xml = inputObj.ToXml();
207             var startTime = DateTime.Now; //開始時間
208             string response = HttpService.Post(xml, sendUrl, false, timeOut);//調用HTTP通訊接口提交數據
209             var endTime = DateTime.Now; //結束時間
210             int timeCost = (int)((endTime - startTime).TotalMilliseconds); //計算所用時間
211             //將xml格式的數據轉化爲對象以返回
212             WxPayData result = new WxPayData();
213             result.FromXml(response, jsApiConfig.Key);
214             ReportCostTime(paymentId, sendUrl, timeCost, result);//測速上報
215             return result;
216         }
217 
218     }
219 }
JsApiPay.cs

第二部分 微信H5支付安全

微信H5支付是微信官方2017年上半年剛剛對外開放的支付模式,它主要應用於在手機網站在移動瀏覽器(非微信環境)調用微信支付的場景。服務器

注意:微信H5支付須要在微信支付商戶平臺單獨申請開通,不然沒法使用。

微信H5支付的流程比較簡單,就是拼接請求的xml數據,進行統一下單,獲取到支付的mweb_url,而後請求這個url網址就行。

H5Config.cs

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 
 6 namespace Gwbnsh.API.Payment.wxpay
 7 {
 8     /// <summary>
 9     /// 移動端非微信瀏覽器支付
10     /// </summary>
11     public class H5Config
12     {
13         #region 字段
14         private string partner = string.Empty;
15         private string key = string.Empty;
16         private string appid = string.Empty;
17         private string notify_url = string.Empty;
18         #endregion
19 
20         public H5Config(int site_payment_id)
21         {
22             Model.site_payment model = new BLL.site_payment().GetModel(site_payment_id); //站點支付方式
23             if (model != null)
24             {
25                 Model.payment payModel = new BLL.payment().GetModel(model.payment_id); //支付平臺
26                 Model.sites siteModel = new BLL.sites().GetModel(model.site_id); //站點配置
27                 Model.sysconfig sysConfig = new BLL.sysconfig().loadConfig(); //系統配置
28 
29                 partner = model.key1; //商戶號(必須配置)
30                 key = model.key2; //商戶支付密鑰,參考開戶郵件設置(必須配置)
31                 appid = model.key3; //綁定支付的APPID(必須配置)
32                 notify_url = "";
33             }
34         }
35 
36         #region 屬性
37         /// <summary>
38         /// 商戶號(必須配置)
39         /// </summary>
40         public string Partner
41         {
42             get { return partner; }
43             set { partner = value; }
44         }
45 
46         /// <summary>
47         /// 獲取或設交易安全校驗碼
48         /// </summary>
49         public string Key
50         {
51             get { return key; }
52             set { key = value; }
53         }
54 
55         /// <summary>
56         /// 綁定支付的APPID(必須配置)
57         /// </summary>
58         public string AppId
59         {
60             get { return appid; }
61             set { appid = value; }
62         }
63 
64         /// <summary>
65         /// 獲取服務器異步通知頁面路徑
66         /// </summary>
67         public string Notify_url
68         {
69             get { return notify_url; }
70         }
71 
72         #endregion
73     }
74 }
H5Config.cs

H5Pay.cs

  1 using Gwbnsh.Common;
  2 using System;
  3 using System.Collections.Generic;
  4 using System.Linq;
  5 using System.Text;
  6 using System.Web;
  7 
  8 namespace Gwbnsh.API.Payment.wxpay
  9 {
 10     public class H5Pay
 11     {
 12         /**
 13         * 
 14         * 測速上報
 15         * @param string interface_url 接口URL
 16         * @param int timeCost 接口耗時
 17         * @param WxPayData inputObj參數數組
 18         */
 19         public static void ReportCostTime(int paymentId, string interface_url, int timeCost, WxPayData inputObj)
 20         {
 21             //若是僅失敗上報
 22             if (inputObj.IsSet("return_code") && inputObj.GetValue("return_code").ToString() == "SUCCESS" &&
 23              inputObj.IsSet("result_code") && inputObj.GetValue("result_code").ToString() == "SUCCESS")
 24             {
 25                 return;
 26             }
 27 
 28             //上報邏輯
 29             WxPayData data = new WxPayData();
 30             data.SetValue("interface_url", interface_url);
 31             data.SetValue("execute_time_", timeCost);
 32             //返回狀態碼
 33             if (inputObj.IsSet("return_code"))
 34             {
 35                 data.SetValue("return_code", inputObj.GetValue("return_code"));
 36             }
 37             //返回信息
 38             if (inputObj.IsSet("return_msg"))
 39             {
 40                 data.SetValue("return_msg", inputObj.GetValue("return_msg"));
 41             }
 42             //業務結果
 43             if (inputObj.IsSet("result_code"))
 44             {
 45                 data.SetValue("result_code", inputObj.GetValue("result_code"));
 46             }
 47             //錯誤代碼
 48             if (inputObj.IsSet("err_code"))
 49             {
 50                 data.SetValue("err_code", inputObj.GetValue("err_code"));
 51             }
 52             //錯誤代碼描述
 53             if (inputObj.IsSet("err_code_des"))
 54             {
 55                 data.SetValue("err_code_des", inputObj.GetValue("err_code_des"));
 56             }
 57             //商戶訂單號
 58             if (inputObj.IsSet("out_trade_no"))
 59             {
 60                 data.SetValue("out_trade_no", inputObj.GetValue("out_trade_no"));
 61             }
 62             //設備號
 63             if (inputObj.IsSet("device_info"))
 64             {
 65                 data.SetValue("device_info", inputObj.GetValue("device_info"));
 66             }
 67 
 68             try
 69             {
 70                 Report(paymentId, data);
 71             }
 72             catch (WxPayException ex)
 73             {
 74                 //不作任何處理
 75             }
 76         }
 77 
 78         /**
 79         * 
 80         * 測速上報接口實現
 81         * @param WxPayData inputObj 提交給測速上報接口的參數
 82         * @param int timeOut 測速上報接口超時時間
 83         * @throws WxPayException
 84         * @return 成功時返回測速上報接口返回的結果,其餘拋異常
 85         */
 86         public static WxPayData Report(int paymentId, WxPayData inputObj, int timeOut = 1)
 87         {
 88             H5Config h5Config = new H5Config(paymentId);
 89             string url = "https://api.mch.weixin.qq.com/payitil/report";
 90             //檢測必填參數
 91             if (!inputObj.IsSet("interface_url"))
 92             {
 93                 throw new WxPayException("接口URL,缺乏必填參數interface_url!");
 94             }
 95             if (!inputObj.IsSet("return_code"))
 96             {
 97                 throw new WxPayException("返回狀態碼,缺乏必填參數return_code!");
 98             }
 99             if (!inputObj.IsSet("result_code"))
100             {
101                 throw new WxPayException("業務結果,缺乏必填參數result_code!");
102             }
103             if (!inputObj.IsSet("user_ip"))
104             {
105                 throw new WxPayException("訪問接口IP,缺乏必填參數user_ip!");
106             }
107             if (!inputObj.IsSet("execute_time_"))
108             {
109                 throw new WxPayException("接口耗時,缺乏必填參數execute_time_!");
110             }
111 
112             inputObj.SetValue("appid", h5Config.AppId);//公衆帳號ID
113             inputObj.SetValue("mch_id", h5Config.Partner);//商戶號
114             inputObj.SetValue("user_ip", DTRequest.GetIP());//終端ip
115             inputObj.SetValue("time", DateTime.Now.ToString("yyyyMMddHHmmss"));//商戶上報時間     
116             inputObj.SetValue("nonce_str", GenerateNonceStr());//隨機字符串
117             inputObj.SetValue("sign", inputObj.MakeSign(h5Config.Key));//簽名
118             string xml = inputObj.ToXml();
119 
120             string response = HttpService.Post(xml, url, false, timeOut);
121 
122             WxPayData result = new WxPayData();
123             result.FromXml(response, h5Config.Key);
124             return result;
125         }
126 
127         /**
128         * 生成時間戳,標準北京時間,時區爲東八區,自1970年1月1日 0點0分0秒以來的秒數
129          * @return 時間戳
130         */
131         public static string GenerateTimeStamp()
132         {
133             TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
134             return Convert.ToInt64(ts.TotalSeconds).ToString();
135         }
136 
137         /**
138         * 生成隨機串,隨機串包含字母或數字
139         * @return 隨機串
140         */
141         public static string GenerateNonceStr()
142         {
143             return Guid.NewGuid().ToString().Replace("-", "");
144         }
145         /// <summary>
146         /// 接收從微信支付後臺發送過來的數據未驗證簽名
147         /// </summary>
148         /// <returns>微信支付後臺返回的數據</returns>
149         public static WxPayData GetNotifyData()
150         {
151             //接收從微信後臺POST過來的數據
152             System.IO.Stream s = HttpContext.Current.Request.InputStream;
153             int count = 0;
154             byte[] buffer = new byte[1024];
155             StringBuilder builder = new StringBuilder();
156             while ((count = s.Read(buffer, 0, 1024)) > 0)
157             {
158                 builder.Append(Encoding.UTF8.GetString(buffer, 0, count));
159             }
160             s.Flush();
161             s.Close();
162             s.Dispose();
163 
164             //轉換數據格式暫不驗證簽名
165             WxPayData data = new WxPayData();
166             try
167             {
168                 data.FromXml(builder.ToString());
169             }
170             catch (WxPayException ex)
171             {
172                 //若簽名錯誤,則當即返回結果給微信支付後臺
173                 WxPayData res = new WxPayData();
174                 res.SetValue("return_code", "FAIL");
175                 res.SetValue("return_msg", ex.Message);
176                 HttpContext.Current.Response.Write(res.ToXml());
177                 HttpContext.Current.Response.End();
178             }
179 
180             return data;
181         }
182 
183         /**
184         *    
185         * 查詢訂單
186         * @param WxPayData inputObj 提交給查詢訂單API的參數
187         * @param int timeOut 超時時間
188         * @throws WxPayException
189         * @return 成功時返回訂單查詢結果,其餘拋異常
190         */
191         public static WxPayData OrderQuery(int paymentId, WxPayData inputObj, int timeOut = 6)
192         {
193             string sendUrl = "https://api.mch.weixin.qq.com/pay/orderquery";
194             //檢測必填參數
195             if (!inputObj.IsSet("out_trade_no") && !inputObj.IsSet("transaction_id"))
196             {
197                 throw new WxPayException("訂單查詢接口中,out_trade_no、transaction_id至少填一個!");
198             }
199             H5Config h5Config = new H5Config(paymentId);
200             inputObj.SetValue("appid", h5Config.AppId);//公衆帳號ID
201             inputObj.SetValue("mch_id", h5Config.Partner);//商戶號
202             inputObj.SetValue("nonce_str", GenerateNonceStr());//隨機字符串
203             inputObj.SetValue("sign", inputObj.MakeSign(h5Config.Key));//簽名
204             string xml = inputObj.ToXml();
205             var startTime = DateTime.Now; //開始時間
206             string response = HttpService.Post(xml, sendUrl, false, timeOut);//調用HTTP通訊接口提交數據
207             var endTime = DateTime.Now; //結束時間
208             int timeCost = (int)((endTime - startTime).TotalMilliseconds); //計算所用時間
209             //將xml格式的數據轉化爲對象以返回
210             WxPayData result = new WxPayData();
211             result.FromXml(response, h5Config.Key);
212             ReportCostTime(paymentId, sendUrl, timeCost, result);//測速上報
213             return result;
214         }
215 
216     }
217 }
H5Pay.cs

第三部分 微信掃碼支付

微信掃碼支付通常應用的場景是PC端電腦支付。微信掃碼支付可分爲兩種模式,根據支付場景選擇相應模式。通常狀況下的PC端掃碼支付選擇的是模式二,須要注意的是模式二無回調函數。

【模式一】商戶後臺系統根據微信支付規則連接生成二維碼,連接中帶固定參數productid(可定義爲產品標識或訂單號)。用戶掃碼後,微信支付系統將productid和用戶惟一標識(openid)回調商戶後臺系統(須要設置支付回調URL),商戶後臺系統根據productid生成支付交易,最後微信支付系統發起用戶支付流程。

【模式二】商戶後臺系統調用微信支付【統一下單API】生成預付交易,將接口返回的連接生成二維碼,用戶掃碼後輸入密碼完成支付交易。注意:該模式的預付單有效期爲2小時,過時後沒法支付。

微信掃碼支付最友好的解決方案就是支付完成以後經過JS設置監聽函數,經過該函數完成跳轉。可參考的代碼以下:

NativeConfig.cs

 1 using System.Web;
 2 using System.Text;
 3 using System.IO;
 4 using System.Net;
 5 using System;
 6 using System.Xml;
 7 using System.Collections.Generic;
 8 using Gwbnsh.Common;
 9 
10 namespace Gwbnsh.API.Payment.wxpay
11 {
12     public class NativeConfig
13     {
14         #region 字段
15         private string partner = string.Empty;
16         private string key = string.Empty;
17         private string appid = string.Empty;
18         private string notify_url = string.Empty;
19         #endregion
20 
21         public NativeConfig(int site_payment_id)
22         {
23             Model.site_payment model = new BLL.site_payment().GetModel(site_payment_id); //站點支付方式
24             if (model != null)
25             {
26                 Model.payment payModel = new BLL.payment().GetModel(model.payment_id); //支付平臺
27                 Model.sites siteModel = new BLL.sites().GetModel(model.site_id); //站點配置
28                 Model.sysconfig sysConfig = new BLL.sysconfig().loadConfig(); //系統配置
29 
30                 partner = model.key1; //商戶號(必須配置)
31                 key = model.key2; //商戶支付密鑰,參考開戶郵件設置(必須配置)
32                 appid = model.key3; //綁定支付的APPID(必須配置)
33                 notify_url = "";
34             }
35         }
36 
37         #region 屬性
38         /// <summary>
39         /// 商戶號(必須配置)
40         /// </summary>
41         public string Partner
42         {
43             get { return partner; }
44             set { partner = value; }
45         }
46 
47         /// <summary>
48         /// 獲取或設交易安全校驗碼
49         /// </summary>
50         public string Key
51         {
52             get { return key; }
53             set { key = value; }
54         }
55 
56         /// <summary>
57         /// 綁定支付的APPID(必須配置)
58         /// </summary>
59         public string AppId
60         {
61             get { return appid; }
62             set { appid = value; }
63         }
64 
65         /// <summary>
66         /// 獲取服務器異步通知頁面路徑
67         /// </summary>
68         public string Notify_url
69         {
70             get { return notify_url; }
71         }
72 
73         #endregion
74     }
75 }
NativeConfig.cs

NativePay.cs

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Web;
  4 using System.Net;
  5 using System.IO;
  6 using System.Text;
  7 using Gwbnsh.Common;
  8 
  9 namespace Gwbnsh.API.Payment.wxpay
 10 {
 11     public class NativePay
 12     {
 13         /**
 14         * 
 15         * 測速上報
 16         * @param string interface_url 接口URL
 17         * @param int timeCost 接口耗時
 18         * @param WxPayData inputObj參數數組
 19         */
 20         public static void ReportCostTime(int paymentId, string interface_url, int timeCost, WxPayData inputObj)
 21         {
 22             //若是僅失敗上報
 23             if (inputObj.IsSet("return_code") && inputObj.GetValue("return_code").ToString() == "SUCCESS" &&
 24              inputObj.IsSet("result_code") && inputObj.GetValue("result_code").ToString() == "SUCCESS")
 25             {
 26                 return;
 27             }
 28 
 29             //上報邏輯
 30             WxPayData data = new WxPayData();
 31             data.SetValue("interface_url", interface_url);
 32             data.SetValue("execute_time_", timeCost);
 33             //返回狀態碼
 34             if (inputObj.IsSet("return_code"))
 35             {
 36                 data.SetValue("return_code", inputObj.GetValue("return_code"));
 37             }
 38             //返回信息
 39             if (inputObj.IsSet("return_msg"))
 40             {
 41                 data.SetValue("return_msg", inputObj.GetValue("return_msg"));
 42             }
 43             //業務結果
 44             if (inputObj.IsSet("result_code"))
 45             {
 46                 data.SetValue("result_code", inputObj.GetValue("result_code"));
 47             }
 48             //錯誤代碼
 49             if (inputObj.IsSet("err_code"))
 50             {
 51                 data.SetValue("err_code", inputObj.GetValue("err_code"));
 52             }
 53             //錯誤代碼描述
 54             if (inputObj.IsSet("err_code_des"))
 55             {
 56                 data.SetValue("err_code_des", inputObj.GetValue("err_code_des"));
 57             }
 58             //商戶訂單號
 59             if (inputObj.IsSet("out_trade_no"))
 60             {
 61                 data.SetValue("out_trade_no", inputObj.GetValue("out_trade_no"));
 62             }
 63             //設備號
 64             if (inputObj.IsSet("device_info"))
 65             {
 66                 data.SetValue("device_info", inputObj.GetValue("device_info"));
 67             }
 68 
 69             try
 70             {
 71                 Report(paymentId, data);
 72             }
 73             catch (WxPayException ex)
 74             {
 75                 //不作任何處理
 76             }
 77         }
 78 
 79         /**
 80         * 
 81         * 測速上報接口實現
 82         * @param WxPayData inputObj 提交給測速上報接口的參數
 83         * @param int timeOut 測速上報接口超時時間
 84         * @throws WxPayException
 85         * @return 成功時返回測速上報接口返回的結果,其餘拋異常
 86         */
 87         public static WxPayData Report(int paymentId, WxPayData inputObj, int timeOut = 1)
 88         {
 89             NativeConfig nativeConfig = new NativeConfig(paymentId);
 90             string url = "https://api.mch.weixin.qq.com/payitil/report";
 91             //檢測必填參數
 92             if (!inputObj.IsSet("interface_url"))
 93             {
 94                 throw new WxPayException("接口URL,缺乏必填參數interface_url!");
 95             }
 96             if (!inputObj.IsSet("return_code"))
 97             {
 98                 throw new WxPayException("返回狀態碼,缺乏必填參數return_code!");
 99             }
100             if (!inputObj.IsSet("result_code"))
101             {
102                 throw new WxPayException("業務結果,缺乏必填參數result_code!");
103             }
104             if (!inputObj.IsSet("user_ip"))
105             {
106                 throw new WxPayException("訪問接口IP,缺乏必填參數user_ip!");
107             }
108             if (!inputObj.IsSet("execute_time_"))
109             {
110                 throw new WxPayException("接口耗時,缺乏必填參數execute_time_!");
111             }
112 
113             inputObj.SetValue("appid", nativeConfig.AppId);//公衆帳號ID
114             inputObj.SetValue("mch_id", nativeConfig.Partner);//商戶號
115             inputObj.SetValue("user_ip", DTRequest.GetIP());//終端ip
116             inputObj.SetValue("time", DateTime.Now.ToString("yyyyMMddHHmmss"));//商戶上報時間     
117             inputObj.SetValue("nonce_str", GenerateNonceStr());//隨機字符串
118             inputObj.SetValue("sign", inputObj.MakeSign(nativeConfig.Key));//簽名
119             string xml = inputObj.ToXml();
120 
121             string response = HttpService.Post(xml, url, false, timeOut);
122 
123             WxPayData result = new WxPayData();
124             result.FromXml(response, nativeConfig.Key);
125             return result;
126         }
127 
128         /**
129         * 生成時間戳,標準北京時間,時區爲東八區,自1970年1月1日 0點0分0秒以來的秒數
130          * @return 時間戳
131         */
132         public static string GenerateTimeStamp()
133         {
134             TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
135             return Convert.ToInt64(ts.TotalSeconds).ToString();
136         }
137 
138         /**
139         * 生成隨機串,隨機串包含字母或數字
140         * @return 隨機串
141         */
142         public static string GenerateNonceStr()
143         {
144             return Guid.NewGuid().ToString().Replace("-", "");
145         }
146         /// <summary>
147         /// 接收從微信支付後臺發送過來的數據未驗證簽名
148         /// </summary>
149         /// <returns>微信支付後臺返回的數據</returns>
150         public static WxPayData GetNotifyData()
151         {
152             //接收從微信後臺POST過來的數據
153             System.IO.Stream s = HttpContext.Current.Request.InputStream;
154             int count = 0;
155             byte[] buffer = new byte[1024];
156             StringBuilder builder = new StringBuilder();
157             while ((count = s.Read(buffer, 0, 1024)) > 0)
158             {
159                 builder.Append(Encoding.UTF8.GetString(buffer, 0, count));
160             }
161             s.Flush();
162             s.Close();
163             s.Dispose();
164 
165             //轉換數據格式暫不驗證簽名
166             WxPayData data = new WxPayData();
167             try
168             {
169                 data.FromXml(builder.ToString());
170             }
171             catch (WxPayException ex)
172             {
173                 //若簽名錯誤,則當即返回結果給微信支付後臺
174                 WxPayData res = new WxPayData();
175                 res.SetValue("return_code", "FAIL");
176                 res.SetValue("return_msg", ex.Message);
177                 HttpContext.Current.Response.Write(res.ToXml());
178                 HttpContext.Current.Response.End();
179             }
180 
181             return data;
182         }
183 
184         /**
185         *    
186         * 查詢訂單
187         * @param WxPayData inputObj 提交給查詢訂單API的參數
188         * @param int timeOut 超時時間
189         * @throws WxPayException
190         * @return 成功時返回訂單查詢結果,其餘拋異常
191         */
192         public static WxPayData OrderQuery(int paymentId, WxPayData inputObj, int timeOut = 6)
193         {
194             string sendUrl = "https://api.mch.weixin.qq.com/pay/orderquery";
195             //檢測必填參數
196             if (!inputObj.IsSet("out_trade_no") && !inputObj.IsSet("transaction_id"))
197             {
198                 throw new WxPayException("訂單查詢接口中,out_trade_no、transaction_id至少填一個!");
199             }
200             NativeConfig nativeConfig = new NativeConfig(paymentId);
201             inputObj.SetValue("appid", nativeConfig.AppId);//公衆帳號ID
202             inputObj.SetValue("mch_id", nativeConfig.Partner);//商戶號
203             inputObj.SetValue("nonce_str", GenerateNonceStr());//隨機字符串
204             inputObj.SetValue("sign", inputObj.MakeSign(nativeConfig.Key));//簽名
205             string xml = inputObj.ToXml();
206             var startTime = DateTime.Now; //開始時間
207             string response = HttpService.Post(xml, sendUrl, false, timeOut);//調用HTTP通訊接口提交數據
208             var endTime = DateTime.Now; //結束時間
209             int timeCost = (int)((endTime - startTime).TotalMilliseconds); //計算所用時間
210             //將xml格式的數據轉化爲對象以返回
211             WxPayData result = new WxPayData();
212             result.FromXml(response, nativeConfig.Key);
213             ReportCostTime(paymentId, sendUrl, timeCost, result);//測速上報
214             return result;
215         }
216 
217     }
218 }
NativePay.cs

如下爲掃碼支付、H5支付以及公衆號支付須要用到的共同類:

HttpService.cs

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Web;
  4 using System.Net;
  5 using System.IO;
  6 using System.Text;
  7 using System.Net.Security;
  8 using System.Security.Authentication;
  9 using System.Security.Cryptography.X509Certificates;
 10 
 11 namespace Gwbnsh.API.Payment.wxpay
 12 {
 13     /// <summary>
 14     /// http鏈接基礎類,負責底層的http通訊
 15     /// </summary>
 16     public class HttpService
 17     {
 18         public static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
 19         {
 20             //直接確認,不然打不開    
 21             return true;
 22         }
 23 
 24         public static string Post(string xml, string url, bool isUseCert, int timeout)
 25         {
 26             System.GC.Collect();//垃圾回收,回收沒有正常關閉的http鏈接
 27 
 28             string result = "";//返回結果
 29 
 30             HttpWebRequest request = null;
 31             HttpWebResponse response = null;
 32             Stream reqStream = null;
 33 
 34             try
 35             {
 36                 //設置最大鏈接數
 37                 ServicePointManager.DefaultConnectionLimit = 200;
 38                 //設置https驗證方式
 39                 if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
 40                 {
 41                     ServicePointManager.ServerCertificateValidationCallback =
 42                             new RemoteCertificateValidationCallback(CheckValidationResult);
 43                 }
 44 
 45                 /***************************************************************
 46                 * 下面設置HttpWebRequest的相關屬性
 47                 * ************************************************************/
 48                 request = (HttpWebRequest)WebRequest.Create(url);
 49 
 50                 request.Method = "POST";
 51                 request.Timeout = timeout * 1000;
 52 
 53                 //設置代理服務器
 54                 /*WebProxy proxy = new WebProxy();                          //定義一個網關對象
 55                 proxy.Address = new Uri(WxPayConfig.PROXY_URL);              //網關服務器端口:端口
 56                 request.Proxy = proxy;*/
 57 
 58                 //設置POST的數據類型和長度
 59                 request.ContentType = "text/xml";
 60                 byte[] data = System.Text.Encoding.UTF8.GetBytes(xml);
 61                 request.ContentLength = data.Length;
 62 
 63                 //是否使用證書
 64                 /*if (isUseCert)
 65                 {
 66                     string path = HttpContext.Current.Request.PhysicalApplicationPath;
 67                     X509Certificate2 cert = new X509Certificate2(path + WxPayConfig.SSLCERT_PATH, WxPayConfig.SSLCERT_PASSWORD);
 68                     request.ClientCertificates.Add(cert);
 69                 }*/
 70 
 71                 //往服務器寫入數據
 72                 reqStream = request.GetRequestStream();
 73                 reqStream.Write(data, 0, data.Length);
 74                 reqStream.Close();
 75 
 76                 //獲取服務端返回
 77                 response = (HttpWebResponse)request.GetResponse();
 78 
 79                 //獲取服務端返回數據
 80                 StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
 81                 result = sr.ReadToEnd().Trim();
 82                 sr.Close();
 83             }
 84             catch (System.Threading.ThreadAbortException e)
 85             {
 86                 System.Threading.Thread.ResetAbort();
 87             }
 88             catch (WebException e)
 89             {
 90                 throw new WxPayException(e.ToString());
 91             }
 92             catch (Exception e)
 93             {
 94                 throw new WxPayException(e.ToString());
 95             }
 96             finally
 97             {
 98                 //關閉鏈接和流
 99                 if (response != null)
100                 {
101                     response.Close();
102                 }
103                 if (request != null)
104                 {
105                     request.Abort();
106                 }
107             }
108             return result;
109         }
110 
111         /// <summary>
112         /// 處理http GET請求,返回數據
113         /// </summary>
114         /// <param name="url">請求的url地址</param>
115         /// <returns>http GET成功後返回的數據,失敗拋WebException異常</returns>
116         public static string Get(string url)
117         {
118             System.GC.Collect();
119             string result = "";
120 
121             HttpWebRequest request = null;
122             HttpWebResponse response = null;
123 
124             //請求url以獲取數據
125             try
126             {
127                 //設置最大鏈接數
128                 ServicePointManager.DefaultConnectionLimit = 200;
129                 //設置https驗證方式
130                 if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
131                 {
132                     ServicePointManager.ServerCertificateValidationCallback =
133                             new RemoteCertificateValidationCallback(CheckValidationResult);
134                 }
135 
136                 /***************************************************************
137                 * 下面設置HttpWebRequest的相關屬性
138                 * ************************************************************/
139                 request = (HttpWebRequest)WebRequest.Create(url);
140 
141                 request.Method = "GET";
142 
143                 //設置代理
144                 /*WebProxy proxy = new WebProxy();
145                 proxy.Address = new Uri(WxPayConfig.PROXY_URL);
146                 request.Proxy = proxy;*/
147 
148                 //獲取服務器返回
149                 response = (HttpWebResponse)request.GetResponse();
150 
151                 //獲取HTTP返回數據
152                 StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
153                 result = sr.ReadToEnd().Trim();
154                 sr.Close();
155             }
156             catch (System.Threading.ThreadAbortException e)
157             {
158                 System.Threading.Thread.ResetAbort();
159             }
160             catch (WebException e)
161             {
162                 throw new WxPayException(e.ToString());
163             }
164             catch (Exception e)
165             {
166                 throw new WxPayException(e.ToString());
167             }
168             finally
169             {
170                 //關閉鏈接和流
171                 if (response != null)
172                 {
173                     response.Close();
174                 }
175                 if (request != null)
176                 {
177                     request.Abort();
178                 }
179             }
180             return result;
181         }
182     }
183 }
HttpService.cs

WxPayData.cs

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Web;
  4 using System.Xml;
  5 using System.Security.Cryptography;
  6 using System.Text;
  7 using Gwbnsh.Common;
  8 
  9 namespace Gwbnsh.API.Payment.wxpay
 10 {
 11     /// <summary>
 12     /// 微信支付協議接口數據類,全部的API接口通訊都依賴這個數據結構,
 13     /// 在調用接口以前先填充各個字段的值,而後進行接口通訊,
 14     /// 這樣設計的好處是可擴展性強,用戶可隨意對協議進行更改而不用從新設計數據結構,
 15     /// 還能夠隨意組合出不一樣的協議數據包,不用爲每一個協議設計一個數據包結構
 16     /// </summary>
 17     public class WxPayData
 18     {
 19         public WxPayData()
 20         {
 21 
 22         }
 23 
 24         //採用排序的Dictionary的好處是方便對數據包進行簽名,不用再簽名以前再作一次排序
 25         private SortedDictionary<string, object> m_values = new SortedDictionary<string, object>();
 26 
 27         /**
 28         * 設置某個字段的值
 29         * @param key 字段名
 30          * @param value 字段值
 31         */
 32         public void SetValue(string key, object value)
 33         {
 34             m_values[key] = value;
 35         }
 36 
 37         /**
 38         * 根據字段名獲取某個字段的值
 39         * @param key 字段名
 40          * @return key對應的字段值
 41         */
 42         public object GetValue(string key)
 43         {
 44             object o = null;
 45             m_values.TryGetValue(key, out o);
 46             return o;
 47         }
 48 
 49         /**
 50          * 判斷某個字段是否已設置
 51          * @param key 字段名
 52          * @return 若字段key已被設置,則返回true,不然返回false
 53          */
 54         public bool IsSet(string key)
 55         {
 56             object o = null;
 57             m_values.TryGetValue(key, out o);
 58             if (null != o)
 59                 return true;
 60             else
 61                 return false;
 62         }
 63 
 64         /**
 65         * @將Dictionary轉成xml
 66         * @return 經轉換獲得的xml串
 67         * @throws WxPayException
 68         **/
 69         public string ToXml()
 70         {
 71             //數據爲空時不能轉化爲xml格式
 72             if (0 == m_values.Count)
 73             {
 74                 throw new WxPayException("WxPayData數據爲空!");
 75             }
 76 
 77             string xml = "<xml>";
 78             foreach (KeyValuePair<string, object> pair in m_values)
 79             {
 80                 //字段值不能爲null,會影響後續流程
 81                 if (pair.Value == null)
 82                 {
 83                     throw new WxPayException("WxPayData內部含有值爲null的字段!");
 84                 }
 85 
 86                 if (pair.Value.GetType() == typeof(int))
 87                 {
 88                     xml += "<" + pair.Key + ">" + pair.Value + "</" + pair.Key + ">";
 89                 }
 90                 else if (pair.Value.GetType() == typeof(string))
 91                 {
 92                     xml += "<" + pair.Key + ">" + "<![CDATA[" + pair.Value + "]]></" + pair.Key + ">";
 93                 }
 94                 else//除了string和int類型不能含有其餘數據類型
 95                 {
 96                     throw new WxPayException("WxPayData字段數據類型錯誤!");
 97                 }
 98             }
 99             xml += "</xml>";
100             return xml;
101         }
102 
103         /**
104         * @接收從微信後臺POST過來的數據(未驗證簽名)
105         * @return 經轉換獲得的Dictionary
106         * @throws WxPayException
107         */
108         public SortedDictionary<string, object> GetRequest()
109         {
110             //接收從微信後臺POST過來的數據
111             System.IO.Stream s = HttpContext.Current.Request.InputStream;
112             int count = 0;
113             byte[] buffer = new byte[1024];
114             StringBuilder builder = new StringBuilder();
115             while ((count = s.Read(buffer, 0, 1024)) > 0)
116             {
117                 builder.Append(Encoding.UTF8.GetString(buffer, 0, count));
118             }
119             s.Flush();
120             s.Close();
121             s.Dispose();
122 
123             if (string.IsNullOrEmpty(builder.ToString()))
124             {
125                 throw new WxPayException("將空的xml串轉換爲WxPayData不合法!");
126             }
127 
128             XmlDocument xmlDoc = new XmlDocument();
129             xmlDoc.LoadXml(builder.ToString());
130             XmlNode xmlNode = xmlDoc.FirstChild;//獲取到根節點<xml>
131             XmlNodeList nodes = xmlNode.ChildNodes;
132             foreach (XmlNode xn in nodes)
133             {
134                 XmlElement xe = (XmlElement)xn;
135                 m_values[xe.Name] = xe.InnerText;//獲取xml的鍵值對到WxPayData內部的數據中
136             }
137 
138             return m_values;
139         }
140 
141         /**
142         * @將xml轉爲WxPayData對象並返回對象內部的數據
143         * @param string 待轉換的xml串
144         * @return 經轉換獲得的Dictionary
145         * @throws WxPayException
146         */
147         public SortedDictionary<string, object> FromXml(string xml, string key)
148         {
149             if (string.IsNullOrEmpty(xml))
150             {
151                 throw new WxPayException("將空的xml串轉換爲WxPayData不合法!");
152             }
153 
154             XmlDocument xmlDoc = new XmlDocument();
155             xmlDoc.LoadXml(xml);
156             XmlNode xmlNode = xmlDoc.FirstChild;//獲取到根節點<xml>
157             XmlNodeList nodes = xmlNode.ChildNodes;
158             foreach (XmlNode xn in nodes)
159             {
160                 XmlElement xe = (XmlElement)xn;
161                 m_values[xe.Name] = xe.InnerText;//獲取xml的鍵值對到WxPayData內部的數據中
162             }
163 
164             try
165             {
166                 //2015-06-29 錯誤是沒有簽名
167                 if (m_values["return_code"] != "SUCCESS")
168                 {
169                     return m_values;
170                 }
171                 CheckSign(key);//驗證簽名,不經過會拋異常
172             }
173             catch (Exception ex)
174             {
175                 throw new WxPayException(ex.Message);
176             }
177 
178             return m_values;
179         }
180         /**
181        * @將xml轉爲WxPayData對象並返回對象內部的數據(未驗證簽名)
182        * @param string 待轉換的xml串
183        * @return 經轉換獲得的Dictionary
184        * @throws WxPayException
185        */
186         public SortedDictionary<string, object> FromXml(string xml)
187         {
188             if (string.IsNullOrEmpty(xml))
189             {
190                 throw new WxPayException("將空的xml串轉換爲WxPayData不合法!");
191             }
192 
193             XmlDocument xmlDoc = new XmlDocument();
194             xmlDoc.LoadXml(xml);
195             XmlNode xmlNode = xmlDoc.FirstChild;//獲取到根節點<xml>
196             XmlNodeList nodes = xmlNode.ChildNodes;
197             foreach (XmlNode xn in nodes)
198             {
199                 XmlElement xe = (XmlElement)xn;
200                 m_values[xe.Name] = xe.InnerText;//獲取xml的鍵值對到WxPayData內部的數據中
201             }
202 
203             try
204             {
205                 //2015-06-29 錯誤是沒有簽名
206                 if (m_values["return_code"] != "SUCCESS")
207                 {
208                     return m_values;
209                 }
210             }
211             catch (Exception ex)
212             {
213                 throw new WxPayException(ex.Message);
214             }
215 
216             return m_values;
217         }
218         /**
219         * @Dictionary格式轉化成url參數格式
220         * @ return url格式串, 該串不包含sign字段值
221         */
222         public string ToUrl()
223         {
224             string buff = "";
225             foreach (KeyValuePair<string, object> pair in m_values)
226             {
227                 if (pair.Value == null)
228                 {
229                     throw new WxPayException("WxPayData內部含有值爲null的字段!");
230                 }
231 
232                 if (pair.Key != "sign" && pair.Value.ToString() != "")
233                 {
234                     buff += pair.Key + "=" + pair.Value + "&";
235                 }
236             }
237             buff = buff.Trim('&');
238             return buff;
239         }
240 
241 
242         /**
243         * @Dictionary格式化成Json
244          * @return json串數據
245         */
246         public string ToJson()
247         {
248             string jsonStr = JsonHelper.ObjectToJSON(m_values);
249             return jsonStr;
250         }
251 
252         /**
253         * @values格式化成能在Web頁面上顯示的結果(由於web頁面上不能直接輸出xml格式的字符串)
254         */
255         public string ToPrintStr()
256         {
257             string str = "";
258             foreach (KeyValuePair<string, object> pair in m_values)
259             {
260                 if (pair.Value == null)
261                 {
262                     throw new WxPayException("WxPayData內部含有值爲null的字段!");
263                 }
264 
265                 str += string.Format("{0}={1}<br>", pair.Key, pair.Value.ToString());
266             }
267             return str;
268         }
269 
270         /**
271         * @生成簽名,詳見簽名生成算法
272         * @return 簽名, sign字段不參加簽名
273         */
274         public string MakeSign(string key)
275         {
276             //轉url格式
277             string str = ToUrl();
278             //在string後加入API KEY
279             str += "&key=" + key;
280             //MD5加密
281             var md5 = MD5.Create();
282             var bs = md5.ComputeHash(Encoding.UTF8.GetBytes(str));
283             var sb = new StringBuilder();
284             foreach (byte b in bs)
285             {
286                 sb.Append(b.ToString("x2"));
287             }
288             //全部字符轉爲大寫
289             return sb.ToString().ToUpper();
290         }
291 
292         /**
293         * 
294         * 檢測簽名是否正確
295         * 正確返回true,錯誤拋異常
296         */
297         public bool CheckSign(string key)
298         {
299             //若是沒有設置簽名,則跳過檢測
300             if (!IsSet("sign"))
301             {
302                 throw new WxPayException("WxPayData簽名存在但不合法!");
303             }
304             //若是設置了簽名可是簽名爲空,則拋異常
305             else if (GetValue("sign") == null || GetValue("sign").ToString() == "")
306             {
307                 throw new WxPayException("WxPayData簽名存在但不合法!");
308             }
309 
310             //獲取接收到的簽名
311             string return_sign = GetValue("sign").ToString();
312 
313             //在本地計算新的簽名
314             string cal_sign = MakeSign(key);
315 
316             if (cal_sign == return_sign)
317             {
318                 return true;
319             }
320 
321             throw new WxPayException("WxPayData簽名驗證錯誤!");
322         }
323 
324         /**
325         * @獲取Dictionary
326         */
327         public SortedDictionary<string, object> GetValues()
328         {
329             return m_values;
330         }
331     }
332 }
WxPayData.cs

WxPayException.cs

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Web;
 4 
 5 namespace Gwbnsh.API.Payment.wxpay
 6 {
 7     public class WxPayException : Exception 
 8     {
 9         public WxPayException(string msg) : base(msg)
10         {
11 
12         }
13     }
14 }
WxPayException.cs

最後,總結一下上述幾種支付方式須要注意的點。

1. 全部的支付參數都須要到微信支付商戶平臺(pay.weixin.qq.com)配置參數。

2. 微信公衆號支付、微信掃碼支付須要在微信公衆號裏面申請開通;H5支付須要在微信商戶平臺申請開通。

3. 僅有公衆號支付和掃碼支付一模式需配置支付域名,H5無需配置域名,可是使用的網站域名和申請時填寫的要一致。

4. 全部使用JS API方式發起支付請求的連接地址,都必須在當前頁面所配置的支付受權目錄之下。

5. 當公衆平臺接到掃碼支付請求時,會回調當前頁面所配置的支付回調連接傳遞訂單信息。

如下爲源碼,包含aspx頁面文件和詳細使用說明:下載

相關文章
相關標籤/搜索