.Net后台实现微信APP支付

时间:2019-01-13 19:09:10   收藏:0   阅读:203

上一节分享了微信小程序支付的后台,这一节来分享一下微信APP支付的后台。微信APP支付和微信小程序差别不大,微信APP支付后台不需要微信登录凭证、后台下单时交易类型(trade_type)不再是"JSAPI",而是“APP”、商户后台传递给支付端的下单参数也有所不同。由于微信小程序支付和APP支付使用的APPID不同,索性直接写了两套支付,不再在代码里区分究竟该使用小程序支付的配置参数还是APP支付的参数。

官方是这样介绍的

技术分享图片
具体实现:

新建AppPayConfig类

技术分享图片
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 using System.Web.Configuration;
 7 
 8 namespace App.Pay.WePay.XcxPay
 9 {
10     public class XcxPayConfig : WePayConfig
11     {
12         //=======【基本信息设置】=====================================
13         /* 微信公众号信息配置
14         * APPID:绑定支付的APPID(必须配置)
15         * MCHID:商户号(必须配置)
16         * KEY:商户支付密钥,参考开户邮件设置(必须配置)
17         * APPSECRET:公众帐号secert(仅JSAPI支付的时候需要配置)
18         */
19         /// 小程序支付
20         public static string APPID = WebConfigurationManager.AppSettings["XcxAppID"].ToString();
21         public static string MCHID = WebConfigurationManager.AppSettings["XcxMchID"].ToString();
22         public static string KEY = WebConfigurationManager.AppSettings["XcxKey"].ToString();
23         public static string APPSECRET = WebConfigurationManager.AppSettings["XcxAppSecret"].ToString();
24 
25         //=======【证书路径设置】===================================== 
26         /* 证书路径,注意应该填写绝对路径(仅退款、撤销订单时需要)
27         */
28         public const string SSLCERT_PATH = "cert/apiclient_cert.p12";
29         public const string SSLCERT_PASSWORD = "1233410002";
30 
31         //=======【支付结果通知url】===================================== 
32         /* 支付结果通知回调url,用于商户接收支付结果
33         */
34         public static string NOTIFY_URL = WebConfigurationManager.AppSettings["XcxNotifyUrl"].ToString();
35 
36         // log记录
37         public static string LogPath = WebConfigurationManager.AppSettings["XcxLog"].ToString();
38     }
39 }
View Code

新建AppPayHttpService类

技术分享图片
  1 using System;
  2 using System.Collections.Generic;
  3 using System.IO;
  4 using System.Linq;
  5 using System.Net;
  6 using System.Net.Security;
  7 using System.Security.Cryptography.X509Certificates;
  8 using System.Text;
  9 using System.Threading.Tasks;
 10 using System.Web;
 11 
 12 namespace App.Pay.WePay.AppPay
 13 {
 14     public class AppPayHttpService
 15     {
 16         private static Log Log = new Log(AppPayConfig.LogPath);
 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 + AppPayConfig.SSLCERT_PATH, AppPayConfig.SSLCERT_PASSWORD);
 68                     request.ClientCertificates.Add(cert);
 69                     //Log.Debug("WxPayApi", "PostXml used cert");
 70                 }
 71 
 72                 //往服务器写入数据
 73                 reqStream = request.GetRequestStream();
 74                 reqStream.Write(data, 0, data.Length);
 75                 reqStream.Close();
 76 
 77                 //获取服务端返回
 78                 response = (HttpWebResponse)request.GetResponse();
 79 
 80                 //获取服务端返回数据
 81                 StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
 82                 result = sr.ReadToEnd().Trim();
 83                 sr.Close();
 84             }
 85             catch (System.Threading.ThreadAbortException e)
 86             {
 87                 Log.Error("HttpService", "Thread - caught ThreadAbortException - resetting.");
 88                 Log.Error("Exception message: {0}", e.Message);
 89                 System.Threading.Thread.ResetAbort();
 90             }
 91             catch (WebException e)
 92             {
 93                 Log.Error("HttpService", e.ToString());
 94                 if (e.Status == WebExceptionStatus.ProtocolError)
 95                 {
 96                     Log.Error("HttpService", "StatusCode : " + ((HttpWebResponse)e.Response).StatusCode);
 97                     Log.Error("HttpService", "StatusDescription : " + ((HttpWebResponse)e.Response).StatusDescription);
 98                 }
 99                 throw new WePayException(e.ToString());
100             }
101             catch (Exception e)
102             {
103                 Log.Error("HttpService", e.ToString());
104                 throw new WePayException(e.ToString());
105             }
106             finally
107             {
108                 //关闭连接和流
109                 if (response != null)
110                 {
111                     response.Close();
112                 }
113                 if (request != null)
114                 {
115                     request.Abort();
116                 }
117             }
118             return result;
119         }
120 
121         /// <summary>
122         /// 处理http GET请求,返回数据
123         /// </summary>
124         /// <param name="url">请求的url地址</param>
125         /// <returns>http GET成功后返回的数据,失败抛WebException异常</returns>
126         public static string Get(string url)
127         {
128             System.GC.Collect();
129             string result = "";
130 
131             HttpWebRequest request = null;
132             HttpWebResponse response = null;
133 
134             //请求url以获取数据
135             try
136             {
137                 //设置最大连接数
138                 ServicePointManager.DefaultConnectionLimit = 200;
139                 //设置https验证方式
140                 if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
141                 {
142                     ServicePointManager.ServerCertificateValidationCallback =
143                             new RemoteCertificateValidationCallback(CheckValidationResult);
144                 }
145 
146                 /***************************************************************
147                 * 下面设置HttpWebRequest的相关属性
148                 * ************************************************************/
149                 request = (HttpWebRequest)WebRequest.Create(url);
150 
151                 request.Method = "GET";
152 
153                 //设置代理
154                 //WebProxy proxy = new WebProxy();
155                 //proxy.Address = new Uri(WxPayConfig.PROXY_URL);
156                 //request.Proxy = proxy;
157 
158                 //获取服务器返回
159                 response = (HttpWebResponse)request.GetResponse();
160 
161                 //获取HTTP返回数据
162                 StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
163                 result = sr.ReadToEnd().Trim();
164                 sr.Close();
165             }
166             catch (System.Threading.ThreadAbortException e)
167             {
168                 Log.Error("HttpService", "Thread - caught ThreadAbortException - resetting.");
169                 Log.Error("Exception message: {0}", e.Message);
170                 System.Threading.Thread.ResetAbort();
171             }
172             catch (WebException e)
173             {
174                 Log.Error("HttpService", e.ToString());
175                 if (e.Status == WebExceptionStatus.ProtocolError)
176                 {
177                     Log.Error("HttpService", "StatusCode : " + ((HttpWebResponse)e.Response).StatusCode);
178                     Log.Error("HttpService", "StatusDescription : " + ((HttpWebResponse)e.Response).StatusDescription);
179                 }
180                 throw new WePayException(e.ToString());
181             }
182             catch (Exception e)
183             {
184                 Log.Error("HttpService", e.ToString());
185                 throw new WePayException(e.ToString());
186             }
187             finally
188             {
189                 //关闭连接和流
190                 if (response != null)
191                 {
192                     response.Close();
193                 }
194                 if (request != null)
195                 {
196                     request.Abort();
197                 }
198             }
199             return result;
200         }
201     }
202 }
View Code

新建AppPayData类

技术分享图片
  1 using LitJson;
  2 using System;
  3 using System.Collections.Generic;
  4 using System.Linq;
  5 using System.Security.Cryptography;
  6 using System.Text;
  7 using System.Threading.Tasks;
  8 using System.Xml;
  9 
 10 namespace App.Pay.WePay.AppPay
 11 {
 12     /// <summary>
 13     /// 微信支付协议接口数据类,所有的API接口通信都依赖这个数据结构,
 14     /// 在调用接口之前先填充各个字段的值,然后进行接口通信,
 15     /// 这样设计的好处是可扩展性强,用户可随意对协议进行更改而不用重新设计数据结构,
 16     /// 还可以随意组合出不同的协议数据包,不用为每个协议设计一个数据包结构
 17     /// </summary>
 18     public class AppPayData
 19     {
 20         private Log Log = new Log(AppPayConfig.LogPath);
 21 
 22         public AppPayData()
 23         {
 24         }
 25 
 26         //采用排序的Dictionary的好处是方便对数据包进行签名,不用再签名之前再做一次排序
 27         private SortedDictionary<string, object> m_values = new SortedDictionary<string, object>();
 28 
 29         /**
 30         * 设置某个字段的值
 31         * @param key 字段名
 32          * @param value 字段值
 33         */
 34         public void SetValue(string key, object value)
 35         {
 36             m_values[key] = value;
 37         }
 38 
 39         /**
 40         * 根据字段名获取某个字段的值
 41         * @param key 字段名
 42          * @return key对应的字段值
 43         */
 44         public object GetValue(string key)
 45         {
 46             object o = null;
 47             m_values.TryGetValue(key, out o);
 48             return o;
 49         }
 50 
 51         /**
 52          * 判断某个字段是否已设置
 53          * @param key 字段名
 54          * @return 若字段key已被设置,则返回true,否则返回false
 55          */
 56         public bool IsSet(string key)
 57         {
 58             object o = null;
 59             m_values.TryGetValue(key, out o);
 60             if (null != o)
 61                 return true;
 62             else
 63                 return false;
 64         }
 65 
 66         /**
 67         * @将Dictionary转成xml
 68         * @return 经转换得到的xml串
 69         * @throws WePayException
 70         **/
 71         public string ToXml()
 72         {
 73             //数据为空时不能转化为xml格式
 74             if (0 == m_values.Count)
 75             {
 76                 Log.Error(this.GetType().ToString(), "WxPayData数据为空!");
 77                 throw new WePayException("WxPayData数据为空!");
 78             }
 79 
 80             string xml = "<xml>";
 81             foreach (KeyValuePair<string, object> pair in m_values)
 82             {
 83                 //字段值不能为null,会影响后续流程
 84                 if (pair.Value == null)
 85                 {
 86                     Log.Error(this.GetType().ToString(), "WxPayData内部含有值为null的字段!");
 87                     throw new WePayException("WxPayData内部含有值为null的字段!");
 88                 }
 89 
 90                 if (pair.Value.GetType() == typeof(int))
 91                 {
 92                     xml += "<" + pair.Key + ">" + pair.Value + "</" + pair.Key + ">";
 93                 }
 94                 else if (pair.Value.GetType() == typeof(string))
 95                 {
 96                     xml += "<" + pair.Key + ">" + "<![CDATA[" + pair.Value + "]]></" + pair.Key + ">";
 97                 }
 98                 else//除了string和int类型不能含有其他数据类型
 99                 {
100                     Log.Error(this.GetType().ToString(), "WxPayData字段数据类型错误!");
101                     throw new WePayException("WxPayData字段数据类型错误!");
102                 }
103             }
104             xml += "</xml>";
105             return xml;
106         }
107 
108         /**
109         * @将xml转为WxPayData对象并返回对象内部的数据
110         * @param string 待转换的xml串
111         * @return 经转换得到的Dictionary
112         * @throws WePayException
113         */
114         public SortedDictionary<string, object> FromXml(string xml)
115         {
116             if (string.IsNullOrEmpty(xml))
117             {
118                 Log.Error(this.GetType().ToString(), "将空的xml串转换为WxPayData不合法!");
119                 throw new WePayException("将空的xml串转换为WxPayData不合法!");
120             }
121 
122             SafeXmlDocument xmlDoc = new SafeXmlDocument();
123             xmlDoc.LoadXml(xml);
124             XmlNode xmlNode = xmlDoc.FirstChild;//获取到根节点<xml>
125             XmlNodeList nodes = xmlNode.ChildNodes;
126             foreach (XmlNode xn in nodes)
127             {
128                 XmlElement xe = (XmlElement)xn;
129                 m_values[xe.Name] = xe.InnerText;//获取xml的键值对到WxPayData内部的数据中
130             }
131 
132             try
133             {
134                 //2015-06-29 错误是没有签名
135                 if (m_values["return_code"] != "SUCCESS")
136                 {
137                     return m_values;
138                 }
139                 CheckSign();//验证签名,不通过会抛异常
140             }
141             catch (WePayException ex)
142             {
143                 throw new WePayException(ex.Message);
144             }
145 
146             return m_values;
147         }
148 
149         /**
150         * @Dictionary格式转化成url参数格式
151         * @ return url格式串, 该串不包含sign字段值
152         */
153         public string ToUrl()
154         {
155             string buff = "";
156             foreach (KeyValuePair<string, object> pair in m_values)
157             {
158                 if (pair.Value == null)
159                 {
160                     Log.Error(this.GetType().ToString(), "WxPayData内部含有值为null的字段!");
161                     throw new WePayException("WxPayData内部含有值为null的字段!");
162                 }
163 
164                 if (pair.Key != "sign" && pair.Value.ToString() != "")
165                 {
166                     buff += pair.Key + "=" + pair.Value + "&";
167                 }
168             }
169             buff = buff.Trim(&);
170             return buff;
171         }
172 
173 
174         /**
175         * @Dictionary格式化成Json
176          * @return json串数据
177         */
178         public string ToJson()
179         {
180             string jsonStr = JsonMapper.ToJson(m_values);
181             return jsonStr;
182         }
183 
184         /**
185         * @values格式化成能在Web页面上显示的结果(因为web页面上不能直接输出xml格式的字符串)
186         */
187         public string ToPrintStr()
188         {
189             string str = "";
190             foreach (KeyValuePair<string, object> pair in m_values)
191             {
192                 if (pair.Value == null)
193                 {
194                     Log.Error(this.GetType().ToString(), "WxPayData内部含有值为null的字段!");
195                     throw new WePayException("WxPayData内部含有值为null的字段!");
196                 }
197 
198                 str += string.Format("{0}={1}<br>", pair.Key, pair.Value.ToString());
199             }
200             Log.Debug(this.GetType().ToString(), "Print in Web Page : " + str);
201             return str;
202         }
203 
204         /**
205         * @生成签名,详见签名生成算法
206         * @return 签名, sign字段不参加签名
207         */
208         public string MakeSign()
209         {
210             //转url格式
211             string str = ToUrl();
212             //在string后加入API KEY
213             str += "&key=" + AppPayConfig.KEY;
214             //MD5加密
215             var md5 = MD5.Create();
216             var bs = md5.ComputeHash(Encoding.UTF8.GetBytes(str));
217             var sb = new StringBuilder();
218             foreach (byte b in bs)
219             {
220                 sb.Append(b.ToString("x2"));
221             }
222             //所有字符转为大写
223             return sb.ToString().ToUpper();
224         }
225 
226         /**
227         * 
228         * 检测签名是否正确
229         * 正确返回true,错误抛异常
230         */
231         public bool CheckSign()
232         {
233             //如果没有设置签名,则跳过检测
234             if (!IsSet("sign"))
235             {
236                 Log.Error(this.GetType().ToString(), "WxPayData签名存在但不合法!");
237                 throw new WePayException("WxPayData签名存在但不合法!");
238             }
239             //如果设置了签名但是签名为空,则抛异常
240             else if (GetValue("sign") == null || GetValue("sign").ToString() == "")
241             {
242                 Log.Error(this.GetType().ToString(), "WxPayData签名存在但不合法!");
243                 throw new WePayException("WxPayData签名存在但不合法!");
244             }
245 
246             //获取接收到的签名
247             string return_sign = GetValue("sign").ToString();
248 
249             //在本地计算新的签名
250             string cal_sign = MakeSign();
251 
252             if (cal_sign == return_sign)
253             {
254                 return true;
255             }
256 
257             Log.Error(this.GetType().ToString(), "WxPayData签名验证错误!");
258             throw new WePayException("WxPayData签名验证错误!");
259         }
260 
261         /**
262         * @获取Dictionary
263         */
264         public SortedDictionary<string, object> GetValues()
265         {
266             return m_values;
267         }
268     }
269 }
View Code

新建AppPayNotify类

技术分享图片
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 using System.Web;
 7 
 8 namespace App.Pay.WePay.AppPay
 9 {
10     /// <summary>
11     /// 回调处理基类
12     /// 主要负责接收微信支付后台发送过来的数据,对数据进行签名验证
13     /// 子类在此类基础上进行派生并重写自己的回调处理过程
14     /// </summary>
15     public class AppPayNotify
16     {
17         public HttpContext context { get; set; }
18         public Log Log = new Log(AppPayConfig.LogPath);
19 
20         public AppPayNotify(HttpContext context)
21         {
22             this.context = context;
23         }
24 
25         /// <summary>
26         /// 接收从微信支付后台发送过来的数据并验证签名
27         /// </summary>
28         /// <returns>微信支付后台返回的数据</returns>
29         public AppPayData GetNotifyData()
30         {
31             //接收从微信后台POST过来的数据
32             System.IO.Stream s = context.Request.InputStream;
33             int count = 0;
34             byte[] buffer = new byte[1024];
35             StringBuilder builder = new StringBuilder();
36             while ((count = s.Read(buffer, 0, 1024)) > 0)
37             {
38                 builder.Append(Encoding.UTF8.GetString(buffer, 0, count));
39             }
40             s.Flush();
41             s.Close();
42             s.Dispose();
43 
44             //转换数据格式并验证签名
45             AppPayData data = new AppPayData();
46             try
47             {
48                 data.FromXml(builder.ToString());
49             }
50             catch (WePayException ex)
51             {
52                 //若签名错误,则立即返回结果给微信支付后台
53                 AppPayData res = new AppPayData();
54                 res.SetValue("return_code", "FAIL");
55                 res.SetValue("return_msg", ex.Message);
56                 Log.Error(this.GetType().ToString(), "Sign check error : " + res.ToXml());
57                 context.Response.Write(res.ToXml());
58                 context.Response.End();
59             }
60 
61             Log.Info(this.GetType().ToString(), "Check sign success");
62             return data;
63         }
64 
65         //派生类需要重写这个方法,进行不同的回调处理
66         public virtual void ProcessNotify()
67         {
68 
69         }
70     }
71 }
View Code

新建AppPayApi类

技术分享图片
  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 using System.Threading.Tasks;
  6 
  7 namespace App.Pay.WePay.AppPay
  8 {
  9     public class AppPayApi
 10     {
 11         public static Log Log = new Log(AppPayConfig.LogPath);
 12 
 13         /**
 14         * 提交被扫支付API
 15         * 收银员使用扫码设备读取微信用户刷卡授权码以后,二维码或条码信息传送至商户收银台,
 16         * 由商户收银台或者商户后台调用该接口发起支付。
 17         * @param WxPayData inputObj 提交给被扫支付API的参数
 18         * @param int timeOut 超时时间
 19         * @throws WePayException
 20         * @return 成功时返回调用结果,其他抛异常
 21         */
 22         public static AppPayData Micropay(AppPayData inputObj, int timeOut = 10)
 23         {
 24             string url = "https://api.mch.weixin.qq.com/pay/micropay";
 25             //检测必填参数
 26             if (!inputObj.IsSet("body"))
 27             {
 28                 throw new WePayException("提交被扫支付API接口中,缺少必填参数body!");
 29             }
 30             else if (!inputObj.IsSet("out_trade_no"))
 31             {
 32                 throw new WePayException("提交被扫支付API接口中,缺少必填参数out_trade_no!");
 33             }
 34             else if (!inputObj.IsSet("total_fee"))
 35             {
 36                 throw new WePayException("提交被扫支付API接口中,缺少必填参数total_fee!");
 37             }
 38             else if (!inputObj.IsSet("auth_code"))
 39             {
 40                 throw new WePayException("提交被扫支付API接口中,缺少必填参数auth_code!");
 41             }
 42 
 43             inputObj.SetValue("spbill_create_ip", WePayConfig.IP);//终端ip
 44             inputObj.SetValue("appid", AppPayConfig.APPID);//公众账号ID
 45             inputObj.SetValue("mch_id", AppPayConfig.MCHID);//商户号
 46             inputObj.SetValue("nonce_str", Guid.NewGuid().ToString().Replace("-", ""));//随机字符串
 47             inputObj.SetValue("sign", inputObj.MakeSign());//签名
 48             string xml = inputObj.ToXml();
 49 
 50             var start = DateTime.Now;//请求开始时间
 51 
 52             Log.Info("XcxPayApi", "MicroPay request : " + xml);
 53             string response = AppPayHttpService.Post(xml, url, false, timeOut);//调用HTTP通信接口以提交数据到API
 54             Log.Info("XcxPayApi", "MicroPay response : " + response);
 55 
 56             var end = DateTime.Now;
 57             int timeCost = (int)((end - start).TotalMilliseconds);//获得接口耗时
 58 
 59             //将xml格式的结果转换为对象以返回
 60             AppPayData result = new AppPayData();
 61             result.FromXml(response);
 62 
 63             ReportCostTime(url, timeCost, result);//测速上报
 64 
 65             return result;
 66         }
 67 
 68 
 69         /**
 70         *    
 71         * 查询订单
 72         * @param WxPayData inputObj 提交给查询订单API的参数
 73         * @param int timeOut 超时时间
 74         * @throws WePayException
 75         * @return 成功时返回订单查询结果,其他抛异常
 76         */
 77         public static AppPayData OrderQuery(AppPayData inputObj, int timeOut = 6)
 78         {
 79             string url = "https://api.mch.weixin.qq.com/pay/orderquery";
 80             //检测必填参数
 81             if (!inputObj.IsSet("out_trade_no") && !inputObj.IsSet("transaction_id"))
 82             {
 83                 throw new WePayException("订单查询接口中,out_trade_no、transaction_id至少填一个!");
 84             }
 85 
 86             inputObj.SetValue("appid", AppPayConfig.APPID);//公众账号ID
 87             inputObj.SetValue("mch_id", AppPayConfig.MCHID);//商户号
 88             inputObj.SetValue("nonce_str", GenerateNonceStr());//随机字符串
 89             inputObj.SetValue("sign", inputObj.MakeSign());//签名
 90 
 91             string xml = inputObj.ToXml();
 92 
 93             var start = DateTime.Now;
 94 
 95             Log.Info("XcxPayApi", "OrderQuery request : " + xml);
 96             string response = AppPayHttpService.Post(xml, url, false, timeOut);//调用HTTP通信接口提交数据
 97             Log.Info("XcxPayApi", "OrderQuery response : " + response);
 98 
 99             var end = DateTime.Now;
100             int timeCost = (int)((end - start).TotalMilliseconds);//获得接口耗时
101 
102             //将xml格式的数据转化为对象以返回
103             AppPayData result = new AppPayData();
104             result.FromXml(response);
105 
106             ReportCostTime(url, timeCost, result);//测速上报
107 
108             return result;
109         }
110 
111 
112         /**
113         * 
114         * 撤销订单API接口
115         * @param WxPayData inputObj 提交给撤销订单API接口的参数,out_trade_no和transaction_id必填一个
116         * @param int timeOut 接口超时时间
117         * @throws WePayException
118         * @return 成功时返回API调用结果,其他抛异常
119         */
120         public static AppPayData Reverse(AppPayData inputObj, int timeOut = 6)
121         {
122             string url = "https://api.mch.weixin.qq.com/secapi/pay/reverse";
123             //检测必填参数
124             if (!inputObj.IsSet("out_trade_no") && !inputObj.IsSet("transaction_id"))
125             {
126                 throw new WePayException("撤销订单API接口中,参数out_trade_no和transaction_id必须填写一个!");
127             }
128 
129             inputObj.SetValue("appid", AppPayConfig.APPID);//公众账号ID
130             inputObj.SetValue("mch_id", AppPayConfig.MCHID);//商户号
131             inputObj.SetValue("nonce_str", GenerateNonceStr());//随机字符串
132             inputObj.SetValue("sign", inputObj.MakeSign());//签名
133             string xml = inputObj.ToXml();
134 
135             var start = DateTime.Now;//请求开始时间
136 
137             Log.Info("XcxPayApi", "Reverse request : " + xml);
138 
139             string response = AppPayHttpService.Post(xml, url, true, timeOut);
140 
141             Log.Info("XcxPayApi", "Reverse response : " + response);
142 
143             var end = DateTime.Now;
144             int timeCost = (int)((end - start).TotalMilliseconds);
145 
146             AppPayData result = new AppPayData();
147             result.FromXml(response);
148 
149             ReportCostTime(url, timeCost, result);//测速上报
150 
151             return result;
152         }
153 
154 
155         /**
156         * 
157         * 申请退款
158         * @param WxPayData inputObj 提交给申请退款API的参数
159         * @param int timeOut 超时时间
160         * @throws WePayException
161         * @return 成功时返回接口调用结果,其他抛异常
162         */
163         public static AppPayData Refund(AppPayData inputObj, int timeOut = 6)
164         {
165             string url = "https://api.mch.weixin.qq.com/secapi/pay/refund";
166             //检测必填参数
167             if (!inputObj.IsSet("out_trade_no") && !inputObj.IsSet("transaction_id"))
168             {
169                 throw new WePayException("退款申请接口中,out_trade_no、transaction_id至少填一个!");
170             }
171             else if (!inputObj.IsSet("out_refund_no"))
172             {
173                 throw new WePayException("退款申请接口中,缺少必填参数out_refund_no!");
174             }
175             else if (!inputObj.IsSet("total_fee"))
176             {
177                 throw new WePayException("退款申请接口中,缺少必填参数total_fee!");
178             }
179             else if (!inputObj.IsSet("refund_fee"))
180             {
181                 throw new WePayException("退款申请接口中,缺少必填参数refund_fee!");
182             }
183             else if (!inputObj.IsSet("op_user_id"))
184             {
185                 throw new WePayException("退款申请接口中,缺少必填参数op_user_id!");
186             }
187 
188             inputObj.SetValue("appid", AppPayConfig.APPID);//公众账号ID
189             inputObj.SetValue("mch_id", AppPayConfig.MCHID);//商户号
190             inputObj.SetValue("nonce_str", Guid.NewGuid().ToString().Replace("-", ""));//随机字符串
191             inputObj.SetValue("sign", inputObj.MakeSign());//签名
192 
193             string xml = inputObj.ToXml();
194             var start = DateTime.Now;
195 
196             Log.Info("XcxPayApi", "Refund request : " + xml);
197             string response = AppPayHttpService.Post(xml, url, true, timeOut);//调用HTTP通信接口提交数据到API
198             Log.Info("XcxPayApi", "Refund response : " + response);
199 
200             var end = DateTime.Now;
201             int timeCost = (int)((end - start).TotalMilliseconds);//获得接口耗时
202 
203             //将xml格式的结果转换为对象以返回
204             AppPayData result = new AppPayData();
205             result.FromXml(response);
206 
207             ReportCostTime(url, timeCost, result);//测速上报
208 
209             return result;
210         }
211 
212 
213         /**
214         * 
215         * 查询退款
216         * 提交退款申请后,通过该接口查询退款状态。退款有一定延时,
217         * 用零钱支付的退款20分钟内到账,银行卡支付的退款3个工作日后重新查询退款状态。
218         * out_refund_no、out_trade_no、transaction_id、refund_id四个参数必填一个
219         * @param WxPayData inputObj 提交给查询退款API的参数
220         * @param int timeOut 接口超时时间
221         * @throws WePayException
222         * @return 成功时返回,其他抛异常
223         */
224         public static AppPayData RefundQuery(AppPayData inputObj, int timeOut = 6)
225         {
226             string url = "https://api.mch.weixin.qq.com/pay/refundquery";
227             //检测必填参数
228             if (!inputObj.IsSet("out_refund_no") && !inputObj.IsSet("out_trade_no") &&
229                 !inputObj.IsSet("transaction_id") && !inputObj.IsSet("refund_id"))
230             {
231                 throw new WePayException("退款查询接口中,out_refund_no、out_trade_no、transaction_id、refund_id四个参数必填一个!");
232             }
233 
234             inputObj.SetValue("appid", AppPayConfig.APPID);//公众账号ID
235             inputObj.SetValue("mch_id", AppPayConfig.MCHID);//商户号
236             inputObj.SetValue("nonce_str", GenerateNonceStr());//随机字符串
237             inputObj.SetValue("sign", inputObj.MakeSign());//签名
238 
239             string xml = inputObj.ToXml();
240 
241             var start = DateTime.Now;//请求开始时间
242 
243             Log.Info("XcxPayApi", "RefundQuery request : " + xml);
244             string response = AppPayHttpService.Post(xml, url, false, timeOut);//调用HTTP通信接口以提交数据到API
245             Log.Info("XcxPayApi", "RefundQuery response : " + response);
246 
247             var end = DateTime.Now;
248             int timeCost = (int)((end - start).TotalMilliseconds);//获得接口耗时
249 
250             //将xml格式的结果转换为对象以返回
251             AppPayData result = new AppPayData();
252             result.FromXml(response);
253 
254             ReportCostTime(url, timeCost, result);//测速上报
255 
256             return result;
257         }
258 
259 
260         /**
261         * 下载对账单
262         * @param WxPayData inputObj 提交给下载对账单API的参数
263         * @param int timeOut 接口超时时间
264         * @throws WePayException
265         * @return 成功时返回,其他抛异常
266         */
267         public static AppPayData DownloadBill(AppPayData inputObj, int timeOut = 6)
268         {
269             string url = "https://api.mch.weixin.qq.com/pay/downloadbill";
270             //检测必填参数
271             if (!inputObj.IsSet("bill_date"))
272             {
273                 throw new WePayException("对账单接口中,缺少必填参数bill_date!");
274             }
275 
276             inputObj.SetValue("appid", AppPayConfig.APPID);//公众账号ID
277             inputObj.SetValue("mch_id", AppPayConfig.MCHID);//商户号
278             inputObj.SetValue("nonce_str", GenerateNonceStr());//随机字符串
279             inputObj.SetValue("sign", inputObj.MakeSign());//签名
280 
281             string xml = inputObj.ToXml();
282 
283             Log.Info("XcxPayApi", "DownloadBill request : " + xml);
284             string response = AppPayHttpService.Post(xml, url, false, timeOut);//调用HTTP通信接口以提交数据到API
285             Log.Info("XcxPayApi", "DownloadBill result : " + response);
286 
287             AppPayData result = new AppPayData();
288             //若接口调用失败会返回xml格式的结果
289             if (response.Substring(0, 5) == "<xml>")
290             {
291                 result.FromXml(response);
292             }
293             //接口调用成功则返回非xml格式的数据
294             else
295                 result.SetValue("result", response);
296 
297             return result;
298         }
299 
300 
301         /**
302         * 
303         * 转换短链接
304         * 该接口主要用于扫码原生支付模式一中的二维码链接转成短链接(weixin://wxpay/s/XXXXXX),
305         * 减小二维码数据量,提升扫描速度和精确度。
306         * @param WxPayData inputObj 提交给转换短连接API的参数
307         * @param int timeOut 接口超时时间
308         * @throws WePayException
309         * @return 成功时返回,其他抛异常
310         */
311         public static AppPayData ShortUrl(AppPayData inputObj, int timeOut = 6)
312         {
313             string url = "https://api.mch.weixin.qq.com/tools/shorturl";
314             //检测必填参数
315             if (!inputObj.IsSet("long_url"))
316             {
317                 throw new WePayException("需要转换的URL,签名用原串,传输需URL encode!");
318             }
319 
320             inputObj.SetValue("appid", AppPayConfig.APPID);//公众账号ID
321             inputObj.SetValue("mch_id", AppPayConfig.MCHID);//商户号
322             inputObj.SetValue("nonce_str", GenerateNonceStr());//随机字符串    
323             inputObj.SetValue("sign", inputObj.MakeSign());//签名
324             inputObj.SetValue("device_info", "wxAPP");//设备名称
325             string xml = inputObj.ToXml();
326 
327             var start = DateTime.Now;//请求开始时间
328 
329             Log.Info("XcxPayApi", "ShortUrl request : " + xml);
330             string response = AppPayHttpService.Post(xml, url, false, timeOut);
331             Log.Info("XcxPayApi", "ShortUrl response : " + response);
332 
333             var end = DateTime.Now;
334             int timeCost = (int)((end - start).TotalMilliseconds);
335 
336             AppPayData result = new AppPayData();
337             result.FromXml(response);
338             ReportCostTime(url, timeCost, result);//测速上报
339 
340             return result;
341         }
342 
343 
344         /**
345         * 
346         * 统一下单
347         * @param WxPaydata inputObj 提交给统一下单API的参数
348         * @param int timeOut 超时时间
349         * @throws WePayException
350         * @return 成功时返回,其他抛异常
351         */
352         public static AppPayData UnifiedOrder(AppPayData inputObj, int timeOut = 6)
353         {
354             string url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
355             //检测必填参数
356             if (!inputObj.IsSet("out_trade_no"))
357             {
358                 throw new WePayException("缺少统一支付接口必填参数out_trade_no!");
359             }
360             else if (!inputObj.IsSet("body"))
361             {
362                 throw new WePayException("缺少统一支付接口必填参数body!");
363             }
364             else if (!inputObj.IsSet("total_fee"))
365             {
366                 throw new WePayException("缺少统一支付接口必填参数total_fee!");
367             }
368             else if (!inputObj.IsSet("trade_type"))
369             {
370                 throw new WePayException("缺少统一支付接口必填参数trade_type!");
371             }
372 
373             //关联参数
374             if (inputObj.GetValue("trade_type").ToString() == "JSAPI" && !inputObj.IsSet("openid"))
375             {
376                 throw new WePayException("统一支付接口中,缺少必填参数openid!trade_type为JSAPI时,openid为必填参数!");
377             }
378             if (inputObj.GetValue("trade_type").ToString() == "NATIVE" && !inputObj.IsSet("product_id"))
379             {
380                 throw new WePayException("统一支付接口中,缺少必填参数product_id!trade_type为JSAPI时,product_id为必填参数!");
381             }
382 
383             //异步通知url未设置,则使用配置文件中的url
384             if (!inputObj.IsSet("notify_url"))
385             {
386                 inputObj.SetValue("notify_url", AppPayConfig.NOTIFY_URL);//异步通知url
387             }
388 
389             inputObj.SetValue("appid", AppPayConfig.APPID);//公众账号ID
390             inputObj.SetValue("mch_id", AppPayConfig.MCHID);//商户号
391             inputObj.SetValue("spbill_create_ip", WePayConfig.IP);//终端ip              
392             inputObj.SetValue("nonce_str", GenerateNonceStr());//随机字符串
393 
394             //签名
395             inputObj.SetValue("sign", inputObj.MakeSign());
396             string xml = inputObj.ToXml();
397 
398             var start = DateTime.Now;
399 
400             Log.Info("XcxPayApi", "UnfiedOrder request : " + xml);
401             string response = AppPayHttpService.Post(xml, url, false, timeOut);
402             Log.Info("XcxPayApi", "UnfiedOrder response : " + response);
403 
404             var end = DateTime.Now;
405             int timeCost = (int)((end - start).TotalMilliseconds);
406 
407             AppPayData result = new AppPayData();
408             result.FromXml(response);
409 
410             ReportCostTime(url, timeCost, result);//测速上报
411 
412             return result;
413         }
414 
415         /**
416         * 
417         * 统一下单
418         * @param WxPaydata inputObj 提交给统一下单API的参数
419         * @param int timeOut 超时时间
420         * @throws WePayException
421         * @return 成功时返回,其他抛异常
422         */
423         public static AppPayData UnifiedOrderApp(AppPayData inputObj, int timeOut = 6)
424         {
425             string url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
426             //检测必填参数
427             if (!inputObj.IsSet("out_trade_no"))
428             {
429                 throw new WePayException("缺少统一支付接口必填参数out_trade_no!");
430             }
431             else if (!inputObj.IsSet("body"))
432             {
433                 throw new WePayException("缺少统一支付接口必填参数body!");
434             }
435             else if (!inputObj.IsSet("total_fee"))
436             {
437                 throw new WePayException("缺少统一支付接口必填参数total_fee!");
438             }
439             else if (!inputObj.IsSet("trade_type"))
440             {
441                 throw new WePayException("缺少统一支付接口必填参数trade_type!");
442             }
443 
444             //关联参数
445             if (inputObj.GetValue("trade_type").ToString() == "JSAPI" && !inputObj.IsSet("openid"))
446             {
447                 throw new WePayException("统一支付接口中,缺少必填参数openid!trade_type为JSAPI时,openid为必填参数!");
448             }
449             if (inputObj.GetValue("trade_type").ToString() == "NATIVE" && !inputObj.IsSet("product_id"))
450             {
451                 throw new WePayException("统一支付接口中,缺少必填参数product_id!trade_type为JSAPI时,product_id为必填参数!");
452             }
453 
454             //异步通知url未设置,则使用配置文件中的url
455             if (!inputObj.IsSet("notify_url"))
456             {
457                 inputObj.SetValue("notify_url", AppPayConfig.NOTIFY_URL);//异步通知url
458             }
459 
460             inputObj.SetValue("appid", AppPayConfig.APPID);//公众账号ID
461             inputObj.SetValue("mch_id", AppPayConfig.MCHID);//商户号
462             inputObj.SetValue("spbill_create_ip", WePayConfig.IP);//终端ip              
463             inputObj.SetValue("nonce_str", GenerateNonceStr());//随机字符串
464 
465             //签名
466             inputObj.SetValue("sign", inputObj.MakeSign());
467             string xml = inputObj.ToXml();
468 
469             var start = DateTime.Now;
470 
471             Log.Info("XcxPayApi", "UnfiedOrder request : " + xml);
472             string response = AppPayHttpService.Post(xml, url, false, timeOut);
473             Log.Info("XcxPayApi", "UnfiedOrder response : " + response);
474 
475             var end = DateTime.Now;
476             int timeCost = (int)((end - start).TotalMilliseconds);
477 
478             AppPayData result = new AppPayData();
479             result.FromXml(response);
480 
481             ReportCostTime(url, timeCost, result);//测速上报
482 
483             return result;
484         }
485 
486 
487         /**
488         * 
489         * 关闭订单
490         * @param WxPayData inputObj 提交给关闭订单API的参数
491         * @param int timeOut 接口超时时间
492         * @throws WePayException
493         * @return 成功时返回,其他抛异常
494         */
495         public static AppPayData CloseOrder(AppPayData inputObj, int timeOut = 6)
496         {
497             string url = "https://api.mch.weixin.qq.com/pay/closeorder";
498             //检测必填参数
499             if (!inputObj.IsSet("out_trade_no"))
500             {
501                 throw new WePayException("关闭订单接口中,out_trade_no必填!");
502             }
503 
504             inputObj.SetValue("appid", AppPayConfig.APPID);//公众账号ID
505             inputObj.SetValue("mch_id", AppPayConfig.MCHID);//商户号
506             inputObj.SetValue("nonce_str", GenerateNonceStr());//随机字符串        
507             inputObj.SetValue("sign", inputObj.MakeSign());//签名
508             string xml = inputObj.ToXml();
509 
510             var start = DateTime.Now;//请求开始时间
511 
512             string response = AppPayHttpService.Post(xml, url, false, timeOut);
513 
514             var end = DateTime.Now;
515             int timeCost = (int)((end - start).TotalMilliseconds);
516 
517             AppPayData result = new AppPayData();
518             result.FromXml(response);
519 
520             ReportCostTime(url, timeCost, result);//测速上报
521 
522             return result;
523         }
524 
525 
526         /**
527         * 
528         * 测速上报
529         * @param string interface_url 接口URL
530         * @param int timeCost 接口耗时
531         * @param WxPayData inputObj参数数组
532         */
533         private static void ReportCostTime(string interface_url, int timeCost, AppPayData inputObj)
534         {
535             //如果不需要进行上报
536             if (WePayConfig.REPORT_LEVENL == 0)
537             {
538                 return;
539             }
540 
541             //如果仅失败上报
542             if (WePayConfig.REPORT_LEVENL == 1 && inputObj.IsSet("return_code") && inputObj.GetValue("return_code").ToString() == "SUCCESS" &&
543              inputObj.IsSet("result_code") && inputObj.GetValue("result_code").ToString() == "SUCCESS")
544             {
545                 return;
546             }
547 
548             //上报逻辑
549             AppPayData data = new AppPayData();
550             data.SetValue("interface_url", interface_url);
551             data.SetValue("execute_time_", timeCost);
552             //返回状态码
553             if (inputObj.IsSet("return_code"))
554             {
555                 data.SetValue("return_code", inputObj.GetValue("return_code"));
556             }
557             //返回信息
558             if (inputObj.IsSet("return_msg"))
559             {
560                 data.SetValue("return_msg", inputObj.GetValue("return_msg"));
561             }
562             //业务结果
563             if (inputObj.IsSet("result_code"))
564             {
565                 data.SetValue("result_code", inputObj.GetValue("result_code"));
566             }
567             //错误代码
568             if (inputObj.IsSet("err_code"))
569             {
570                 data.SetValue("err_code", inputObj.GetValue("err_code"));
571             }
572             //错误代码描述
573             if (inputObj.IsSet("err_code_des"))
574             {
575                 data.SetValue("err_code_des", inputObj.GetValue("err_code_des"));
576             }
577             //商户订单号
578             if (inputObj.IsSet("out_trade_no"))
579             {
580                 data.SetValue("out_trade_no", inputObj.GetValue("out_trade_no"));
581             }
582             //设备号
583             if (inputObj.IsSet("device_info"))
584             {
585                 data.SetValue("device_info", inputObj.GetValue("device_info"));
586             }
587 
588             try
589             {
590                 Report(data);
591             }
592             catch (WePayException ex)
593             {
594                 //不做任何处理
595             }
596         }
597 
598 
599         /**
600         * 
601         * 测速上报接口实现
602         * @param WxPayData inputObj 提交给测速上报接口的参数
603         * @param int timeOut 测速上报接口超时时间
604         * @throws WePayException
605         * @return 成功时返回测速上报接口返回的结果,其他抛异常
606         */
607         public static AppPayData Report(AppPayData inputObj, int timeOut = 1)
608         {
609             string url = "https://api.mch.weixin.qq.com/payitil/report";
610             //检测必填参数
611             if (!inputObj.IsSet("interface_url"))
612             {
613                 throw new WePayException("接口URL,缺少必填参数interface_url!");
614             }
615             if (!inputObj.IsSet("return_code"))
616             {
617                 throw new WePayException("返回状态码,缺少必填参数return_code!");
618             }
619             if (!inputObj.IsSet("result_code"))
620             {
621                 throw new WePayException("业务结果,缺少必填参数result_code!");
622             }
623             if (!inputObj.IsSet("user_ip"))
624             {
625                 throw new WePayException("访问接口IP,缺少必填参数user_ip!");
626             }
627             if (!inputObj.IsSet("execute_time_"))
628             {
629                 throw new WePayException("接口耗时,缺少必填参数execute_time_!");
630             }
631 
632             inputObj.SetValue("appid", AppPayConfig.APPID);//公众账号ID
633             inputObj.SetValue("mch_id", AppPayConfig.MCHID);//商户号
634             inputObj.SetValue("user_ip", WePayConfig.IP);//终端ip
635             inputObj.SetValue("time", DateTime.Now.ToString("yyyyMMddHHmmss"));//商户上报时间     
636             inputObj.SetValue("nonce_str", GenerateNonceStr());//随机字符串
637             inputObj.SetValue("sign", inputObj.MakeSign());//签名
638             string xml = inputObj.ToXml();
639 
640             Log.Info("XcxPayApi", "Report request : " + xml);
641 
642             string response = AppPayHttpService.Post(xml, url, false, timeOut);
643 
644             Log.Info("XcxPayApi", "Report response : " + response);
645 
646             AppPayData result = new AppPayData();
647             result.FromXml(response);
648             return result;
649         }
650 
651         /**
652         * 根据当前系统时间加随机序列来生成订单号
653          * @return 订单号
654         */
655         public static string GenerateOutTradeNo()
656         {
657             var ran = new Random();
658             return string.Format("{0}{1}{2}", AppPayConfig.MCHID, DateTime.Now.ToString("yyyyMMddHHmmss"), ran.Next(999));
659         }
660 
661         /**
662         * 生成时间戳,标准北京时间,时区为东八区,自1970年1月1日 0点0分0秒以来的秒数
663          * @return 时间戳
664         */
665         public static string GenerateTimeStamp()
666         {
667             TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
668             return Convert.ToInt64(ts.TotalSeconds).ToString();
669         }
670 
671         /**
672         * 生成随机串,随机串包含字母或数字
673         * @return 随机串
674         */
675         public static string GenerateNonceStr()
676         {
677             return Guid.NewGuid().ToString().Replace("-", "");
678         }
679     }
680 }
View Code

接下来是业务类,注意业务类中不必再传微信登录凭证。

技术分享图片
  1 using App.Common.Extension;
  2 using App.Pay.WePay.AppPay;
  3 using System;
  4 using System.Collections.Generic;
  5 using System.Linq;
  6 using System.Web;
  7 using System.Web.Configuration;
  8 using System.Web.Mvc;
  9 
 10 namespace App.WebTest.Controllers
 11 {
 12     public class WeAppPayController : BaseController
 13     {
 14         /// <summary>
 15         /// 微信app支付
 16         /// </summary>
 17         /// <param name="oidStr">订单编号</param>
 18         /// <returns></returns>
 19         public ActionResult WxPayApp(string oidStr)
 20         {
 21             // App调用只能传参
 22             int[] oIds = Serialize.JsonTo<List<int>>(oidStr).ToArray();
 23 
 24             #region 验证订单是否有效
 25 
 26             decimal payPrice = 0;
 27             string detail = "";
 28 
 29             /// 验证订单是否有效,并统计订单总金额
 30             /// ...
 31 
 32             #endregion
 33 
 34             #region 统一下单
 35             try
 36             {
 37                 //string userId = LoginUser.Id.ToString();
 38                 var address = WebConfigurationManager.AppSettings["WxAppNotifyUrl"].ToString();
 39                 AppPayData data = new AppPayData();
 40                 data.SetValue("body", "民政社工培训-课程购买");
 41                 //data.SetValue("attach", userId + "|" + String.Join(",", oIds).ToString());
 42                 data.SetValue("attach", String.Join(",", oIds).ToString());
 43                 Random rd = new Random();
 44                 var payNum = DateTime.Now.ToString("yyyyMMddHHmmss") + rd.Next(0, 1000).ToString().PadLeft(3, 0);
 45                 data.SetValue("out_trade_no", payNum);
 46                 data.SetValue("detail", detail.Substring(0, detail.Length - 1));
 47                 data.SetValue("total_fee", Convert.ToInt32(payPrice * 100));
 48                 data.SetValue("time_start", DateTime.Now.ToString("yyyyMMddHHmmss"));
 49                 data.SetValue("time_expire", DateTime.Now.AddMinutes(10).ToString("yyyyMMddHHmmss"));
 50                 data.SetValue("notify_url", address);
 51 
 52                 //注意,这里交易方式是APP
 53                 data.SetValue("trade_type", "APP");
 54 
 55                 AppPayData result = AppPayApi.UnifiedOrder(data);
 56                 var appid = "";
 57                 var partnerid = "";
 58                 var prepayid = "";
 59                 var package = "";
 60                 var nonceStr = "";
 61                 var timestamp = "";
 62                 var sign = "";
 63                 if (!result.IsSet("appid") || !result.IsSet("prepay_id") || result.GetValue("prepay_id").ToString() == "")
 64                 {
 65                     return Json(false, "下单失败!");
 66                 }
 67                 else
 68                 {
 69                     //统一下单
 70                     /// 修改订单状态
 71                     //OrderBll.Value.UpdateOrderApp(oIds, payNum);
 72 
 73                     appid = result.GetValue("appid").ToString();
 74                     nonceStr = result.GetValue("nonce_str").ToString();
 75                     partnerid = result.GetValue("mch_id").ToString();
 76                     prepayid = result.GetValue("prepay_id").ToString();
 77                     package = "Sign=WXPay";// "prepay_id=" + result.GetValue("prepay_id").ToString();
 78                 }
 79                 var signType = "MD5";
 80                 timestamp = ((DateTime.Now.Ticks - TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)).Ticks) / 10000).ToString();
 81                 AppPayData applet = new AppPayData();
 82                 applet.SetValue("appid", appid);
 83                 applet.SetValue("noncestr", nonceStr);
 84                 applet.SetValue("package", package);
 85                 applet.SetValue("partnerid", partnerid);
 86                 applet.SetValue("prepayid", prepayid);
 87                 //applet.SetValue("signType", signType);
 88                 applet.SetValue("timestamp", timestamp);
 89                 sign = applet.MakeSign();
 90                 return Json(new { appid, partnerid, prepayid, package, nonceStr, timestamp, sign });
 91             }
 92             catch (Exception ex)
 93             {
 94                 return Json(false, "缺少参数");
 95             }
 96 
 97             #endregion
 98 
 99         }
100 
101         /// <summary>
102         /// 微信支付回调
103         /// </summary>
104         /// <returns></returns>
105         public string WxAppNotifyUrl()
106         {
107             Pay.Log Log = new Pay.Log(AppPayConfig.LogPath);
108             Log.Info("WxAppNotifyUrl", "支付回调");
109             AppPayNotify notify = new AppPayNotify(System.Web.HttpContext.Current);
110             AppPayData notifyData = notify.GetNotifyData();
111 
112             //检查支付结果中transaction_id是否存在
113             if (!notifyData.IsSet("transaction_id"))
114             {
115                 //若transaction_id不存在,则立即返回结果给微信支付后台
116                 AppPayData res = new AppPayData();
117                 res.SetValue("return_code", "FAIL");
118                 res.SetValue("return_msg", "支付结果中微信订单号不存在");
119                 Log.Error(this.GetType().ToString(), "The Pay result is error : " + res.ToXml());
120                 Response.Write(res.ToXml());
121                 Response.End();
122             }
123 
124             string transaction_id = notifyData.GetValue("transaction_id").ToString();
125 
126             //查询订单,判断订单真实性
127             if (!AppQueryOrder(transaction_id))
128             {
129                 //若订单查询失败,则立即返回结果给微信支付后台
130                 AppPayData res = new AppPayData();
131                 res.SetValue("return_code", "FAIL");
132                 res.SetValue("return_msg", "订单查询失败");
133                 Log.Error(this.GetType().ToString(), "Order query failure : " + res.ToXml());
134 
135                 Response.Write(res.ToXml());
136                 Response.End();
137             }
138             //查询订单成功
139             else
140             {
141                 AppPayData res = new AppPayData();
142                 res.SetValue("return_code", "SUCCESS");
143                 res.SetValue("return_msg", "OK");
144                 Log.Info(this.GetType().ToString(), "Order query success : " + res.ToXml());
145                 Log.Info(this.GetType().ToString(), "Order query success,notifyData : " + notifyData.ToXml());
146                 var returnCode = notifyData.GetValue("return_code").ToString();
147                 var transactionNo = transaction_id;//微信订单号
148                 var outTradeNo = notifyData.GetValue("out_trade_no").ToString();//自定义订单号
149                 var attach = notifyData.GetValue("attach").ToString();//身份证
150                 var endTime = notifyData.GetValue("time_end").ToString();//交易结束时间
151                 //var body = notifyData.GetValue("body").ToString();//projectIdlist
152                 var totalFee = notifyData.GetValue("total_fee").ToString(); ;//支付金额
153 
154                 int userId = Convert.ToInt32(attach.Split(|)[0]);
155                 string msg;
156                 try
157                 {
158                     ///修改数据库订单状态
159                     //var result = OrderBll.Value.CompleteWePay(userId, totalFee, transactionNo, returnCode, outTradeNo, attach, endTime, out msg);
160                     var result = true;
161 
162                     Log.Info(this.GetType().ToString(), "CompleteWePay:" + result);
163                 }
164                 catch (Exception e)
165                 {
166                     Log.Error(this.GetType().ToString(), "CompleteWePay:" + e.ToString());
167                 }
168 
169                 Response.Write(res.ToXml());
170                 Response.End();
171             }
172 
173             return "";
174         }
175 
176         /// <summary>
177         /// 查询订单
178         /// </summary>
179         /// <param name="transaction_id"></param>
180         /// <returns></returns>
181         private bool AppQueryOrder(string transaction_id)
182         {
183             AppPayData req = new AppPayData();
184             req.SetValue("transaction_id", transaction_id);
185             AppPayData res = AppPayApi.OrderQuery(req);
186             if (res.GetValue("return_code").ToString() == "SUCCESS" && res.GetValue("result_code").ToString() == "SUCCESS")
187             {
188                 return true;
189             }
190             else
191             {
192                 return false;
193             }
194         }
195     }
196 }
View Code

 

评论(0
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!