隐藏

C#版微信公众号支付|微信H5支付|微信扫码支付问题汇总及解决方案总结

发布:2021/11/12 10:52:25作者:管理员 来源:本站 浏览次数:1007

最近负责的一些项目开发,都用到了微信支付(微信公众号支付、微信H5支付、微信扫码支付)。在开发的过程中,在调试支付的过程中,或多或少都遇到了一些问题,今天总结下,分享,留存。代码在文章结尾处,有需要的同学可以下载看下。


先说注意的第一点,所有支付的第一步都是请求统一下单,统一下单,统一下单,请求URL地址:https://api.mch.weixin.qq.com/pay/unifiedorder。


再说一个微信官方提供的一个很重要的工具,微信支付接口签名校验工具(网址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=20_1),此工具旨在帮助开发者检测调用【微信支付接口API】时发送的请求参数中生成的签名是否正确,提交相关信息后可获得签名校验结果。特别实用!特别实用!特别实用!签名只要正确了,一切就OK了!




第一部分 微信公众号支付




微信公众号支付需要配置的参数有:APPID(微信公众号开发者ID)、APPSECRET(微信公众号开发者密码)、MCHID(商户ID)、KEY(商户密钥)。




微信公众号支付应用的场景是在微信内部的H5环境中使用的支付方式。因为要通过网页授权获取用户的OpenId,所以必须要配置网页授权域名。同时要配置JS接口安全域名。


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 }


复制代码


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 }


复制代码


第二部分 微信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 }


复制代码


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 }


复制代码


第三部分 微信扫码支付


微信扫码支付一般应用的场景是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 }


复制代码


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 }


复制代码


以下为扫码支付、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 }


复制代码


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 }


复制代码


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 }


复制代码


最后,总结一下上述几种支付方式需要注意的点。


1. 所有的支付参数都需要到微信支付商户平台(pay.weixin.qq.com)配置参数。


2. 微信公众号支付、微信扫码支付需要在微信公众号里面申请开通;H5支付需要在微信商户平台申请开通。


3. 仅有公众号支付和扫码支付一模式需配置支付域名,H5无需配置域名,但是使用的网站域名和申请时填写的要一致。


4. 所有使用JS API方式发起支付请求的链接地址,都必须在当前页面所配置的支付授权目录之下。


5. 当公众平台接到扫码支付请求时,会回调当前页面所配置的支付回调链接传递订单信息。


以下为源码,包含aspx页面文件和详细使用说明:下载