WeChat.cs 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Xml;
  6. using System.Web;
  7. using System.Security.Cryptography;
  8. using System.Security.Cryptography.X509Certificates;
  9. using System.Net;
  10. using System.IO;
  11. using System.Xml.Linq;
  12. using LitJson;
  13. namespace Common
  14. {
  15. public class WeChat
  16. {
  17. private HttpContext _context;
  18. public WeChat(HttpContext context)
  19. {
  20. _context = context;
  21. }
  22. #region 微信支付预处理订单
  23. public Dictionary<string, string> Pay(string AppId, string MchId, decimal PayMoney, string OrderNo, string SubJect, string Description, string OpenId, string ServerIP, string Key, string NotifyUrl, string Attach = "0")
  24. {
  25. Dictionary<string, string> return_result = new Dictionary<string, string>();
  26. int amount = (int)(PayMoney * 100);
  27. //具体请求参数
  28. var par = new SortedList<string, string>
  29. {
  30. {"appid", AppId},
  31. {"mch_id", MchId},
  32. {"nonce_str", Function.get_Random(12)},
  33. {"body",SubJect},
  34. {"detail",Description},
  35. {"out_trade_no",OrderNo},
  36. {"fee_type","CNY"},
  37. {"total_fee",amount.ToString()},
  38. {"spbill_create_ip",ServerIP},
  39. {"notify_url",NotifyUrl},
  40. {"trade_type","JSAPI"},
  41. {"openid",OpenId},
  42. {"attach",Attach}
  43. };
  44. var postStr = String.Join("&", par.Select(item => String.Format("{0}={1}", item.Key.Trim(), item.Value)).ToArray());
  45. var stringSignTemp = postStr + "&key=" + Key;
  46. Function.WriteLog(stringSignTemp, "微信支付预处理订单");
  47. var wxsign = Function.MD532(stringSignTemp);
  48. par.Add("sign", wxsign);
  49. var postxml = new StringBuilder();
  50. postxml.Append("<xml>");
  51. foreach (var item in par)
  52. {
  53. postxml.AppendFormat("<{0}>{1}</{0}>", item.Key, item.Value);
  54. }
  55. postxml.Append("</xml>");
  56. try
  57. {
  58. var result = Function.PostWebRequest("https://api.mch.weixin.qq.com/pay/unifiedorder", postxml.ToString());
  59. Function.WriteLog(result, "微信支付预处理订单");
  60. XmlDocument doc = new XmlDocument();
  61. doc.LoadXml(result);
  62. string timeStamp = Function.ConvertDateTimeInt(DateTime.Now).ToString();
  63. string nonce_str = Function.get_Random(12);
  64. string package = "prepay_id=" + doc.SelectSingleNode("/xml/prepay_id").InnerText;
  65. var pay_param = new SortedList<string, string>
  66. {
  67. {"appId", AppId},
  68. {"timeStamp", timeStamp},
  69. {"nonceStr", nonce_str},
  70. {"package", package},
  71. {"signType", "MD5"}
  72. };
  73. var pay_param_str = String.Join("&", pay_param.Select(item => String.Format("{0}={1}", item.Key.Trim(), item.Value)).ToArray());
  74. var pay_param_str_sign = pay_param_str + "&key=" + Key;
  75. string paySign = Function.MD532(pay_param_str_sign).ToUpper();
  76. return_result.Add("appId", AppId);
  77. return_result.Add("timeStamp", timeStamp);
  78. return_result.Add("nonce_str", nonce_str);
  79. return_result.Add("package", package);
  80. return_result.Add("paySign", paySign);
  81. }
  82. catch
  83. {
  84. }
  85. return return_result;
  86. }
  87. public Dictionary<string, string> AppPay(string AppId, string MchId, decimal PayMoney, string OrderNo, string SubJect, string Description, string ServerIP, string Key, string NotifyUrl)
  88. {
  89. Dictionary<string, string> return_result = new Dictionary<string, string>();
  90. int amount = (int)(PayMoney * 100);
  91. //具体请求参数
  92. var par = new SortedList<string, string>
  93. {
  94. {"appid", AppId},
  95. {"mch_id", MchId},
  96. {"nonce_str", Function.get_Random(12)},
  97. {"body",SubJect},
  98. {"detail",Description},
  99. {"out_trade_no",OrderNo},
  100. {"fee_type","CNY"},
  101. {"total_fee",amount.ToString()},
  102. {"spbill_create_ip",ServerIP},
  103. {"notify_url",NotifyUrl},
  104. {"trade_type","APP"}
  105. };
  106. var postStr = String.Join("&", par.Select(item => String.Format("{0}={1}", item.Key.Trim(), item.Value)).ToArray());
  107. var stringSignTemp = postStr + "&key=" + Key;
  108. Function.WriteLog(stringSignTemp, "微信支付预处理订单");
  109. var wxsign = Function.MD532(stringSignTemp);
  110. par.Add("sign", wxsign);
  111. var postxml = new StringBuilder();
  112. postxml.Append("<xml>");
  113. foreach (var item in par)
  114. {
  115. postxml.AppendFormat("<{0}>{1}</{0}>", item.Key, item.Value);
  116. }
  117. postxml.Append("</xml>");
  118. try
  119. {
  120. var result = Function.PostWebRequest("https://api.mch.weixin.qq.com/pay/unifiedorder", postxml.ToString());
  121. Function.WriteLog(result, "微信支付预处理订单");
  122. XmlDocument doc = new XmlDocument();
  123. doc.LoadXml(result);
  124. string timeStamp = Function.ConvertDateTimeInt(DateTime.Now).ToString();
  125. string nonce_str = Function.get_Random(12);
  126. string package = "prepay_id=" + doc.SelectSingleNode("/xml/prepay_id").InnerText;
  127. var pay_param = new SortedList<string, string>
  128. {
  129. {"appId", AppId},
  130. {"timeStamp", timeStamp},
  131. {"nonceStr", nonce_str},
  132. {"package", package},
  133. {"signType", "MD5"}
  134. };
  135. var pay_param_str = String.Join("&", pay_param.Select(item => String.Format("{0}={1}", item.Key.Trim(), item.Value)).ToArray());
  136. var pay_param_str_sign = pay_param_str + "&key=" + Key;
  137. string paySign = Function.MD532(pay_param_str_sign).ToUpper();
  138. return_result.Add("appId", AppId);
  139. return_result.Add("timeStamp", timeStamp);
  140. return_result.Add("nonce_str", nonce_str);
  141. return_result.Add("package", package);
  142. return_result.Add("paySign", paySign);
  143. }
  144. catch
  145. {
  146. }
  147. return return_result;
  148. }
  149. #endregion
  150. #region 微信支付预处理订单(H5)
  151. public string PayH5(string AppId, string MchId, decimal PayMoney, string OrderNo, string SubJect, string Description, string ServerIP, string Key, string NotifyUrl, string Attach = "0")
  152. {
  153. string return_result = "";
  154. int amount = (int)(PayMoney * 100);
  155. //具体请求参数
  156. var par = new SortedList<string, string>
  157. {
  158. {"appid", AppId},
  159. {"mch_id", MchId},
  160. {"nonce_str", Function.get_Random(12)},
  161. {"body",SubJect},
  162. {"detail",Description},
  163. {"out_trade_no",OrderNo},
  164. {"fee_type","CNY"},
  165. {"total_fee",amount.ToString()},
  166. {"spbill_create_ip",ServerIP},
  167. {"notify_url",NotifyUrl},
  168. {"trade_type","MWEB"},
  169. {"attach",Attach}
  170. };
  171. var postStr = String.Join("&", par.Select(item => String.Format("{0}={1}", item.Key.Trim(), item.Value)).ToArray());
  172. var stringSignTemp = postStr + "&key=" + Key;
  173. Function.WriteLog(stringSignTemp, "微信支付预处理订单(H5)");
  174. var wxsign = Function.MD532(stringSignTemp);
  175. par.Add("sign", wxsign);
  176. var postxml = new StringBuilder();
  177. postxml.Append("<xml>");
  178. foreach (var item in par)
  179. {
  180. postxml.AppendFormat("<{0}>{1}</{0}>", item.Key, item.Value);
  181. }
  182. postxml.Append("</xml>");
  183. try
  184. {
  185. var result = Function.PostWebRequest("https://api.mch.weixin.qq.com/pay/unifiedorder", postxml.ToString());
  186. Function.WriteLog(result, "微信支付预处理订单(H5)");
  187. XmlDocument doc = new XmlDocument();
  188. doc.LoadXml(result);
  189. return_result = doc.SelectSingleNode("/xml/mweb_url").InnerText;
  190. }
  191. catch (Exception ex)
  192. {
  193. Function.WriteLog(ex.ToString(), "微信支付预处理订单(H5)异常");
  194. }
  195. return return_result;
  196. }
  197. #endregion
  198. #region 微信支付异步通知
  199. public string PayCallBack(string Key, bool IsRedis = false)
  200. {
  201. var backxml = new StringBuilder();
  202. backxml.Append("<xml>");
  203. var logSb = new StringBuilder();//日志
  204. try
  205. {
  206. var syncIOFeature = _context.Features.Get<Microsoft.AspNetCore.Http.Features.IHttpBodyControlFeature>();
  207. if (syncIOFeature != null)
  208. {
  209. syncIOFeature.AllowSynchronousIO = true;
  210. }
  211. //接收从微信后台POST过来的数据
  212. var s = _context.Request.Body;
  213. var count = 0;
  214. var buffer = new byte[1024];
  215. var builder = new StringBuilder();
  216. while ((count = s.Read(buffer, 0, 1024)) > 0)
  217. {
  218. builder.Append(Encoding.UTF8.GetString(buffer, 0, count));
  219. }
  220. s.Flush();
  221. s.Close();
  222. s.Dispose();
  223. Function.WriteLog("\r\n========================\r\n回调通知的原始数据:" + builder.ToString(), "微信支付异步通知");
  224. var mValues = new SortedList<string, string>();
  225. var xmlDoc = new XmlDocument();
  226. xmlDoc.XmlResolver = null;
  227. xmlDoc.LoadXml(builder.ToString());
  228. var xmlNode = xmlDoc.FirstChild;//获取到根节点<xml>
  229. var nodes = xmlNode.ChildNodes;
  230. foreach (var xe in nodes.Cast<XmlElement>())
  231. {
  232. mValues[xe.Name] = xe.InnerText;//获取xml的键值对到WxPayData内部的数据中
  233. }
  234. var buff = mValues.Where(pair => pair.Key != "sign" && pair.Value.ToString() != "").Aggregate("", (current, pair) => current + (pair.Key + "=" + pair.Value + "&"));
  235. buff = buff.Trim('&');
  236. var stringSignTemp = buff + "&key=" + Key;
  237. Function.WriteLog("待签名字符串:" + stringSignTemp, "微信支付异步通知");
  238. //MD5加密
  239. var md5 = MD5.Create();
  240. var bs = md5.ComputeHash(Encoding.UTF8.GetBytes(stringSignTemp));
  241. var sb = new StringBuilder();
  242. foreach (byte b in bs)
  243. {
  244. sb.Append(b.ToString("x2"));
  245. }
  246. //所有字符转为大写
  247. var wxsign = sb.ToString().ToUpper();
  248. Function.WriteLog("签名字符串:" + wxsign, "微信支付异步通知");
  249. //获取接收到的签名
  250. string return_sign = "";
  251. mValues.TryGetValue("sign", out return_sign);
  252. Function.WriteLog("签名字符串比较:" + wxsign + " VS " + return_sign, "微信支付异步通知");
  253. if (wxsign == return_sign)
  254. {
  255. string transaction_id = "";
  256. mValues.TryGetValue("transaction_id", out transaction_id);
  257. string out_trade_no = "";
  258. mValues.TryGetValue("out_trade_no", out out_trade_no);
  259. string result_code = "";
  260. mValues.TryGetValue("result_code", out result_code);
  261. string err_code = "";
  262. mValues.TryGetValue("err_code", out err_code);
  263. string total_fee = "";
  264. mValues.TryGetValue("total_fee", out total_fee);
  265. string openid = "";
  266. mValues.TryGetValue("openid", out openid);
  267. string attach = "";
  268. mValues.TryGetValue("attach", out attach);
  269. Function.WriteLog("transaction_id:" + transaction_id, "微信支付异步通知");
  270. Function.WriteLog("out_trade_no:" + out_trade_no, "微信支付异步通知");
  271. Function.WriteLog("result_code:" + result_code, "微信支付异步通知");
  272. Function.WriteLog("err_code:" + err_code, "微信支付异步通知");
  273. Function.WriteLog("total_fee:" + total_fee, "微信支付异步通知");
  274. Function.WriteLog("openid:" + openid, "微信支付异步通知");
  275. Function.WriteLog("attach:" + attach, "微信支付异步通知");
  276. if (result_code == "SUCCESS")
  277. {
  278. var totalAmount = 0m;
  279. decimal.TryParse(total_fee, out totalAmount);
  280. var payAmount = totalAmount / 100;
  281. Function.WriteLog("out_trade_no:" + out_trade_no, "微信支付异步通知");
  282. if (IsRedis)
  283. {
  284. RedisServer.Cache.LPush("PayCallBack", "{\"out_trade_no\":\"" + out_trade_no + "\",\"transaction_id\":\"" + transaction_id + "\",\"total_fee\":\"" + total_fee + "\",\"pay_mode\":\"2\",\"openid\":\"" + openid + "\",\"attach\":\"" + attach + "\"}");
  285. }
  286. else
  287. {
  288. Function.WritePage("/PayCallBack/", Function.MD5_16(Guid.NewGuid().ToString()) + ".txt", "{\"out_trade_no\":\"" + out_trade_no + "\",\"transaction_id\":\"" + transaction_id + "\",\"total_fee\":\"" + total_fee + "\",\"pay_mode\":\"2\",\"openid\":\"" + openid + "\",\"attach\":\"" + attach + "\"}");
  289. }
  290. backxml.Append("<return_code><![CDATA[SUCCESS]]></return_code>");
  291. backxml.AppendFormat(" <return_msg><![CDATA[{0}]]></return_msg>", err_code);
  292. }
  293. else
  294. {
  295. logSb.AppendFormat(" -->订单状态错误:{0};", err_code);
  296. backxml.Append("<return_code><![CDATA[FAIL]]></return_code>");
  297. backxml.AppendFormat(" <return_msg><![CDATA[{0}]]></return_msg>", err_code);
  298. }
  299. }
  300. else
  301. {
  302. backxml.Append("<return_code><![CDATA[FAIL]]></return_code>");
  303. backxml.AppendFormat(" <return_msg><![CDATA[{0}]]></return_msg>", "签名失败");
  304. Function.WriteLog("微信支付----异步通知执行后日志:" + logSb.ToString(), "微信支付异步通知");
  305. }
  306. }
  307. catch (Exception ex)
  308. {
  309. backxml.Append("<return_code><![CDATA[FAIL]]></return_code>");
  310. backxml.AppendFormat(" <return_msg><![CDATA[{0}]]></return_msg>", "签名失败");
  311. Function.WriteLog("微信支付----异步通知执行后日志:" + ex.ToString(), "微信支付异步通知");
  312. }
  313. backxml.Append("</xml>");
  314. return backxml.ToString();
  315. }
  316. public string PayCallBack2(string Key, string BackContent, bool IsRedis = false)
  317. {
  318. var backxml = new StringBuilder();
  319. backxml.Append("<xml>");
  320. var logSb = new StringBuilder();//日志
  321. try
  322. {
  323. var syncIOFeature = _context.Features.Get<Microsoft.AspNetCore.Http.Features.IHttpBodyControlFeature>();
  324. if (syncIOFeature != null)
  325. {
  326. syncIOFeature.AllowSynchronousIO = true;
  327. }
  328. //接收从微信后台POST过来的数据
  329. var mValues = new SortedList<string, string>();
  330. var xmlDoc = new XmlDocument();
  331. xmlDoc.XmlResolver = null;
  332. xmlDoc.LoadXml(BackContent);
  333. var xmlNode = xmlDoc.FirstChild;//获取到根节点<xml>
  334. var nodes = xmlNode.ChildNodes;
  335. foreach (var xe in nodes.Cast<XmlElement>())
  336. {
  337. mValues[xe.Name] = xe.InnerText;//获取xml的键值对到WxPayData内部的数据中
  338. }
  339. var buff = mValues.Where(pair => pair.Key != "sign" && pair.Value.ToString() != "").Aggregate("", (current, pair) => current + (pair.Key + "=" + pair.Value + "&"));
  340. buff = buff.Trim('&');
  341. var stringSignTemp = buff + "&key=" + Key;
  342. Function.WriteLog("待签名字符串:" + stringSignTemp, "微信支付异步通知");
  343. //MD5加密
  344. var md5 = MD5.Create();
  345. var bs = md5.ComputeHash(Encoding.UTF8.GetBytes(stringSignTemp));
  346. var sb = new StringBuilder();
  347. foreach (byte b in bs)
  348. {
  349. sb.Append(b.ToString("x2"));
  350. }
  351. //所有字符转为大写
  352. var wxsign = sb.ToString().ToUpper();
  353. Function.WriteLog("签名字符串:" + wxsign, "微信支付异步通知");
  354. //获取接收到的签名
  355. string return_sign = "";
  356. mValues.TryGetValue("sign", out return_sign);
  357. Function.WriteLog("签名字符串比较:" + wxsign + " VS " + return_sign, "微信支付异步通知");
  358. if (wxsign == return_sign)
  359. {
  360. string transaction_id = "";
  361. mValues.TryGetValue("transaction_id", out transaction_id);
  362. string out_trade_no = "";
  363. mValues.TryGetValue("out_trade_no", out out_trade_no);
  364. string result_code = "";
  365. mValues.TryGetValue("result_code", out result_code);
  366. string err_code = "";
  367. mValues.TryGetValue("err_code", out err_code);
  368. string total_fee = "";
  369. mValues.TryGetValue("total_fee", out total_fee);
  370. string openid = "";
  371. mValues.TryGetValue("openid", out openid);
  372. string attach = "";
  373. mValues.TryGetValue("attach", out attach);
  374. Function.WriteLog("transaction_id:" + transaction_id, "微信支付异步通知");
  375. Function.WriteLog("out_trade_no:" + out_trade_no, "微信支付异步通知");
  376. Function.WriteLog("result_code:" + result_code, "微信支付异步通知");
  377. Function.WriteLog("err_code:" + err_code, "微信支付异步通知");
  378. Function.WriteLog("total_fee:" + total_fee, "微信支付异步通知");
  379. Function.WriteLog("openid:" + openid, "微信支付异步通知");
  380. Function.WriteLog("attach:" + attach, "微信支付异步通知");
  381. if (result_code == "SUCCESS")
  382. {
  383. var totalAmount = 0m;
  384. decimal.TryParse(total_fee, out totalAmount);
  385. var payAmount = totalAmount / 100;
  386. Function.WriteLog("out_trade_no:" + out_trade_no, "微信支付异步通知");
  387. if (IsRedis)
  388. {
  389. RedisServer.Cache.LPush("PayCallBack", "{\"out_trade_no\":\"" + out_trade_no + "\",\"transaction_id\":\"" + transaction_id + "\",\"total_fee\":\"" + total_fee + "\",\"pay_mode\":\"2\",\"openid\":\"" + openid + "\",\"attach\":\"" + attach + "\"}");
  390. }
  391. else
  392. {
  393. Function.WritePage("/PayCallBack/", Function.MD5_16(Guid.NewGuid().ToString()) + ".txt", "{\"out_trade_no\":\"" + out_trade_no + "\",\"transaction_id\":\"" + transaction_id + "\",\"total_fee\":\"" + total_fee + "\",\"pay_mode\":\"2\",\"openid\":\"" + openid + "\",\"attach\":\"" + attach + "\"}");
  394. }
  395. backxml.Append("<return_code><![CDATA[SUCCESS]]></return_code>");
  396. backxml.AppendFormat(" <return_msg><![CDATA[{0}]]></return_msg>", err_code);
  397. }
  398. else
  399. {
  400. logSb.AppendFormat(" -->订单状态错误:{0};", err_code);
  401. backxml.Append("<return_code><![CDATA[FAIL]]></return_code>");
  402. backxml.AppendFormat(" <return_msg><![CDATA[{0}]]></return_msg>", err_code);
  403. }
  404. }
  405. else
  406. {
  407. backxml.Append("<return_code><![CDATA[FAIL]]></return_code>");
  408. backxml.AppendFormat(" <return_msg><![CDATA[{0}]]></return_msg>", "签名失败");
  409. Function.WriteLog("微信支付----异步通知执行后日志:" + logSb.ToString(), "微信支付异步通知");
  410. }
  411. }
  412. catch (Exception ex)
  413. {
  414. backxml.Append("<return_code><![CDATA[FAIL]]></return_code>");
  415. backxml.AppendFormat(" <return_msg><![CDATA[{0}]]></return_msg>", "签名失败");
  416. Function.WriteLog("微信支付----异步通知执行后日志:" + ex.ToString(), "微信支付异步通知");
  417. }
  418. backxml.Append("</xml>");
  419. return backxml.ToString();
  420. }
  421. #endregion
  422. #region 微信分享
  423. public Dictionary<string, string> Share(string AppId, string AppSecret, string Url, bool CacheToken = true)
  424. {
  425. Dictionary<string, string> result = new Dictionary<string, string>();
  426. try
  427. {
  428. string token = getWXToken(AppId, AppSecret, CacheToken);
  429. string content = Function.GetWebRequest("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + token + "&type=jsapi");
  430. Function.WriteLog("content:" + content, "微信参数检查");
  431. JsonData json = JsonMapper.ToObject(content);
  432. string ticket = "";
  433. if (json["errcode"].ToString() == "0")
  434. {
  435. ticket = json["ticket"].ToString();
  436. }
  437. string noncestr = Function.get_Random(10);
  438. string timestamp = Function.ConvertDateTimeInt(DateTime.Now).ToString();
  439. string sign = "jsapi_ticket=" + ticket + "&noncestr=" + noncestr + "&timestamp=" + timestamp + "&url=" + Url;
  440. Function.WriteLog("sign:" + sign, "微信参数检查");
  441. sign = SHA1(sign);
  442. result.Add("appId", AppId);
  443. result.Add("noncestr", noncestr);
  444. result.Add("timestamp", timestamp);
  445. result.Add("sign", sign);
  446. }
  447. catch (Exception ex)
  448. {
  449. Function.WriteLog(DateTime.Now.ToString() + ":" + ex.ToString(), "获取微信分享参数异常");
  450. }
  451. return result;
  452. }
  453. #endregion
  454. #region 微信退款
  455. public string Refund(string AppId, string MchId,string OrderNo, string TradeNo, decimal TotalPrice, string Key, string CertPath)
  456. {
  457. //生成订单号
  458. var batchNo = DateTime.Now.ToString("HHmmss") + Function.get_Random(28);
  459. var payamount = (TotalPrice * 100).ToString("f0");
  460. //具体请求参数
  461. var parwxrefund = new SortedList<string, string>
  462. {
  463. {"appid", AppId },
  464. {"mch_id",MchId},
  465. {"nonce_str", Function.get_Random(10)},
  466. {"out_trade_no",OrderNo},
  467. //{"transaction_id",TradeNo},
  468. {"out_refund_no",batchNo},
  469. {"total_fee", payamount},
  470. {"refund_fee",payamount},
  471. {"op_user_id",MchId},
  472. };
  473. if (!string.IsNullOrEmpty(TradeNo))
  474. {
  475. parwxrefund.Add("transaction_id", TradeNo);
  476. }
  477. var signStr = String.Join("&", parwxrefund.Select(item => String.Format("{0}={1}", item.Key.Trim(), item.Value)).ToArray());;
  478. var stringSignTemp = signStr + "&key=" + Key;
  479. var wxsign = Function.MD532(stringSignTemp);
  480. parwxrefund.Add("sign", wxsign);
  481. var postxml = new StringBuilder();
  482. postxml.Append("<xml>");
  483. foreach (var item in parwxrefund)
  484. {
  485. postxml.AppendFormat("<{0}>{1}</{0}>", item.Key, item.Value);
  486. }
  487. postxml.Append("</xml>");
  488. //退款接口地址
  489. string url = "https://api.mch.weixin.qq.com/secapi/pay/refund";
  490. //本地或者服务器的证书位置(证书在微信支付申请成功发来的通知邮件中)
  491. string cert = Function.getPath(CertPath);
  492. try
  493. {
  494. var cer = new X509Certificate2(cert, MchId, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);//证书
  495. var webrequest = (HttpWebRequest)HttpWebRequest.Create(url);
  496. webrequest.ClientCertificates.Add(cer);
  497. webrequest.Method = "post";
  498. byte[] postdatabyte = Encoding.UTF8.GetBytes(postxml.ToString());
  499. webrequest.ContentLength = postdatabyte.Length;
  500. Stream stream = webrequest.GetRequestStream();
  501. stream.Write(postdatabyte, 0, postdatabyte.Length);
  502. stream.Close();
  503. var httpWebResponse = (HttpWebResponse)webrequest.GetResponse();
  504. var streamReader = new StreamReader(httpWebResponse.GetResponseStream());
  505. string responseContent = streamReader.ReadToEnd();
  506. Function.WriteLog("微信退款回调内容:" + responseContent, "微信退款");
  507. var res = XDocument.Parse(responseContent);
  508. var xElement = res.Element("xml");
  509. if (xElement != null)
  510. {
  511. var element = xElement.Element("return_code");
  512. if (element != null)
  513. {
  514. var returnCode = element.Value;
  515. if (returnCode.Contains("SUCCESS"))
  516. {
  517. //商户订单号
  518. string out_trade_no = "";
  519. var xElement1 = xElement.Element("out_trade_no");
  520. if (xElement1 != null)
  521. {
  522. out_trade_no = "success|" + xElement1.Value;
  523. Function.WriteLog("微信退款修改订单状态:" + out_trade_no, "微信退款");
  524. }
  525. //业务处理
  526. return out_trade_no;
  527. }
  528. else
  529. {
  530. Function.WriteLog("微信支付----退款接口返回错误:-》》" + responseContent, "微信退款");
  531. //业务处理
  532. return responseContent;
  533. }
  534. }
  535. }
  536. }
  537. catch (Exception ex)
  538. {
  539. Function.WriteLog("微信支付退款----异常:-》》" + ex.ToString(), "微信退款");
  540. //业务处理
  541. return ex.ToString();
  542. }
  543. return "";
  544. }
  545. #endregion
  546. #region 公对零钱
  547. public string Change(string AppId, string MchId, string ServerIP, string OrderNo, string OpenId, decimal TotalPrice, string Detail, string Key, string CertPath)
  548. {
  549. var payamount = (TotalPrice * 100).ToString("f0");
  550. //具体请求参数
  551. var parwxrefund = new SortedList<string, string>
  552. {
  553. {"mch_appid", AppId },
  554. {"mchid",MchId},
  555. {"nonce_str", Function.get_Random(10)},
  556. {"partner_trade_no",OrderNo},
  557. {"openid",OpenId},
  558. {"check_name","NO_CHECK"},
  559. {"amount", payamount},
  560. {"desc",Detail},
  561. {"spbill_create_ip",ServerIP},
  562. };
  563. var signStr = String.Join("&", parwxrefund.Select(item => String.Format("{0}={1}", item.Key.Trim(), item.Value)).ToArray()); ;
  564. var stringSignTemp = signStr + "&key=" + Key;
  565. var wxsign = Function.MD532(stringSignTemp);
  566. parwxrefund.Add("sign", wxsign);
  567. var postxml = new StringBuilder();
  568. postxml.Append("<xml>");
  569. foreach (var item in parwxrefund)
  570. {
  571. postxml.AppendFormat("<{0}>{1}</{0}>", item.Key, item.Value);
  572. }
  573. postxml.Append("</xml>");
  574. //接口地址
  575. string url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
  576. //本地或者服务器的证书位置(证书在微信支付申请成功发来的通知邮件中)
  577. string cert = Function.getPath(CertPath);
  578. try
  579. {
  580. var cer = new X509Certificate2(cert, MchId, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);//证书
  581. var webrequest = (HttpWebRequest)HttpWebRequest.Create(url);
  582. webrequest.ClientCertificates.Add(cer);
  583. webrequest.Method = "post";
  584. byte[] postdatabyte = Encoding.UTF8.GetBytes(postxml.ToString());
  585. webrequest.ContentLength = postdatabyte.Length;
  586. Stream stream = webrequest.GetRequestStream();
  587. stream.Write(postdatabyte, 0, postdatabyte.Length);
  588. stream.Close();
  589. var httpWebResponse = (HttpWebResponse)webrequest.GetResponse();
  590. var streamReader = new StreamReader(httpWebResponse.GetResponseStream());
  591. string responseContent = streamReader.ReadToEnd();
  592. Function.WriteLog("回调内容:" + responseContent, "零钱公对私");
  593. var res = XDocument.Parse(responseContent);
  594. var xElement = res.Element("xml");
  595. if (xElement != null)
  596. {
  597. var element = xElement.Element("return_code");
  598. if (element != null)
  599. {
  600. var returnCode = element.Value;
  601. if (returnCode.Contains("SUCCESS"))
  602. {
  603. //微信付款单号
  604. string payment_no = "";
  605. var xElement1 = xElement.Element("payment_no");
  606. if (xElement1 != null)
  607. {
  608. payment_no = "success|" + xElement1.Value;
  609. Function.WriteLog("微信付款单号:" + payment_no, "零钱公对私");
  610. }
  611. //业务处理
  612. return payment_no;
  613. }
  614. else
  615. {
  616. Function.WriteLog("零钱公对私----接口返回错误:" + responseContent, "零钱公对私");
  617. //业务处理
  618. return responseContent;
  619. }
  620. }
  621. }
  622. }
  623. catch (Exception ex)
  624. {
  625. Function.WriteLog("零钱公对私----异常:" + ex.ToString(), "零钱公对私");
  626. //业务处理
  627. return ex.ToString();
  628. }
  629. return "";
  630. }
  631. #endregion
  632. #region 红包发放
  633. public string RedPackage(string AppId, string MchId, string ServerIP, string OrderNo, string OpenId, decimal TotalPrice, string SendName, string Wishing, string ActName, string Remark, string kind, string Key, string CertPath)
  634. {
  635. var payamount = (TotalPrice * 100).ToString("f0");
  636. //具体请求参数
  637. var parwxrefund = new SortedList<string, string>
  638. {
  639. {"nonce_str", Function.get_Random(10)},
  640. {"mch_billno",OrderNo},
  641. {"mch_id",MchId},
  642. {"wxappid", AppId },
  643. {"send_name",SendName},
  644. {"re_openid",OpenId},
  645. {"total_amount", payamount},
  646. {"total_num","1"},
  647. {"wishing",Wishing},
  648. {"client_ip",ServerIP},
  649. {"act_name",ActName},
  650. {"remark",Remark},
  651. {"scene_id","PRODUCT_"+kind},
  652. };
  653. var signStr = String.Join("&", parwxrefund.Select(item => String.Format("{0}={1}", item.Key.Trim(), item.Value)).ToArray()); ;
  654. var stringSignTemp = signStr + "&key=" + Key;
  655. var wxsign = Function.MD532(stringSignTemp);
  656. parwxrefund.Add("sign", wxsign);
  657. var postxml = new StringBuilder();
  658. postxml.Append("<xml>");
  659. foreach (var item in parwxrefund)
  660. {
  661. postxml.AppendFormat("<{0}>{1}</{0}>", item.Key, item.Value);
  662. }
  663. postxml.Append("</xml>");
  664. Function.WriteLog("请求参数:" + postxml.ToString(), "微信红包发放");
  665. //接口地址
  666. string url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack";
  667. //本地或者服务器的证书位置(证书在微信支付申请成功发来的通知邮件中)
  668. string cert = Function.getPath(CertPath);
  669. try
  670. {
  671. var cer = new X509Certificate2(cert, MchId, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);//证书
  672. var webrequest = (HttpWebRequest)HttpWebRequest.Create(url);
  673. webrequest.ClientCertificates.Add(cer);
  674. webrequest.Method = "post";
  675. byte[] postdatabyte = Encoding.UTF8.GetBytes(postxml.ToString());
  676. webrequest.ContentLength = postdatabyte.Length;
  677. Stream stream = webrequest.GetRequestStream();
  678. stream.Write(postdatabyte, 0, postdatabyte.Length);
  679. stream.Close();
  680. var httpWebResponse = (HttpWebResponse)webrequest.GetResponse();
  681. var streamReader = new StreamReader(httpWebResponse.GetResponseStream());
  682. string responseContent = streamReader.ReadToEnd();
  683. Function.WriteLog("回调内容:" + responseContent, "微信红包发放");
  684. var res = XDocument.Parse(responseContent);
  685. var xElement = res.Element("xml");
  686. if (xElement != null)
  687. {
  688. var element = xElement.Element("return_code");
  689. if (element != null)
  690. {
  691. var returnCode = element.Value;
  692. if (returnCode.Contains("SUCCESS"))
  693. {
  694. //微信付款单号
  695. string payment_no = "";
  696. var xElement1 = xElement.Element("payment_no");
  697. if (xElement1 != null)
  698. {
  699. payment_no = "success|" + xElement1.Value;
  700. Function.WriteLog("微信付款单号:" + payment_no, "微信红包发放");
  701. }
  702. //业务处理
  703. return payment_no;
  704. }
  705. else
  706. {
  707. Function.WriteLog("微信红包发放----接口返回错误:" + responseContent, "微信红包发放");
  708. //业务处理
  709. return responseContent;
  710. }
  711. }
  712. }
  713. }
  714. catch (Exception ex)
  715. {
  716. Function.WriteLog("微信红包发放----异常:" + ex.ToString(), "微信红包发放");
  717. //业务处理
  718. return ex.ToString();
  719. }
  720. return "";
  721. }
  722. #endregion
  723. #region 发送模板消息
  724. public void SendModuleMsg(string AppId, string AppSecret, string OpenId, string TemplateId, string Url, Dictionary<string, string> Msg)
  725. {
  726. string token = getWXToken(AppId, AppSecret);
  727. string MsgData = "";
  728. foreach (string key in Msg.Keys)
  729. {
  730. MsgData += "\"" + key + "\": {" +
  731. "\"value\":\"" + Msg[key] + "\"," +
  732. "\"color\":\"#173177\"" +
  733. "},";
  734. }
  735. MsgData = MsgData.TrimEnd(',');
  736. string requestData = "{" +
  737. "\"touser\":\"" + OpenId + "\"," +
  738. "\"template_id\":\"" + TemplateId + "\"," +
  739. "\"url\":\"" + Url + "\"," +
  740. "\"topcolor\":\"#FF0000\"," +
  741. "\"data\":{" + MsgData +
  742. "}" +
  743. "}";
  744. string result = Function.PostWebRequest("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + token, requestData);
  745. Function.WriteLog(result, "发送模板消息");
  746. }
  747. #endregion
  748. #region 接收事件推送
  749. public void ReceiveEventMsg()
  750. {
  751. try
  752. {
  753. //接收从微信后台POST过来的数据
  754. var s = _context.Request.Body;
  755. var count = 0;
  756. var buffer = new byte[1024];
  757. var builder = new StringBuilder();
  758. while ((count = s.Read(buffer, 0, 1024)) > 0)
  759. {
  760. builder.Append(Encoding.UTF8.GetString(buffer, 0, count));
  761. }
  762. s.Flush();
  763. s.Close();
  764. s.Dispose();
  765. Function.WriteLog("\r\n========================\r\n原始数据:" + builder.ToString(), "接收事件推送");
  766. string json = "";
  767. var mValues = new SortedList<string, string>();
  768. var xmlDoc = new XmlDocument();
  769. xmlDoc.LoadXml(builder.ToString());
  770. var xmlNode = xmlDoc.FirstChild;//获取到根节点<xml>
  771. var nodes = xmlNode.ChildNodes;
  772. foreach (var xe in nodes.Cast<XmlElement>())
  773. {
  774. json = "\"" + xe.Name + "\":\"" + xe.InnerText + "\","; //获取xml的键值对到WxPayData内部的数据中
  775. }
  776. json = json.TrimEnd(',');
  777. Function.WritePage("/ReceiveEventMsg/", Function.MD5_16(Guid.NewGuid().ToString()) + ".txt", "{" + json + "}");
  778. }
  779. catch (Exception ex)
  780. {
  781. Function.WriteLog("微信支付----异步通知执行后日志:" + ex.ToString(), "接收事件推送");
  782. }
  783. }
  784. #endregion
  785. #region 自定3*5义菜单
  786. public string SetMenu(string AppId, string AppSecret, Dictionary<string, Dictionary<string, string>> Menu)
  787. {
  788. string json = "{\"button\":[";
  789. foreach (string key in Menu.Keys)
  790. {
  791. Dictionary<string, string> sub = Menu[key];
  792. if (sub.Count == 1)
  793. {
  794. json += "{\"type\":\"view\",\"name\":\"" + key + "\",\"url\":\"" + sub["url"] + "\"},";
  795. }
  796. else
  797. {
  798. string subjson = "";
  799. foreach (string subkey in sub.Keys)
  800. {
  801. subjson += "{\"type\":\"view\",\"name\":\"" + subkey + "\",\"url\":\"" + sub["url"] + "\"},";
  802. }
  803. subjson = subjson.TrimEnd(',');
  804. json += "{\"type\":\"view\",\"name\":\"" + key + "\",\"sub_button\":[" + subjson + "],";
  805. }
  806. }
  807. json = json.TrimEnd(',');
  808. json += "]}";
  809. string token = getWXToken(AppId, AppSecret);
  810. string result = Function.PostWebRequest("https://api.weixin.qq.com/cgi-bin/menu/create?access_token=" + token, json);
  811. JsonData jsonObj = JsonMapper.ToObject(result);
  812. if (jsonObj["errcode"].ToString() == "0")
  813. {
  814. return "success";
  815. }
  816. return jsonObj["errmsg"].ToString();
  817. }
  818. #endregion
  819. #region 公用方法
  820. public string SHA1(string content)
  821. {
  822. try
  823. {
  824. SHA1 sha1 = new SHA1CryptoServiceProvider();
  825. byte[] bytes_in = Encoding.UTF8.GetBytes(content);
  826. byte[] bytes_out = sha1.ComputeHash(bytes_in);
  827. sha1.Dispose();
  828. string result = BitConverter.ToString(bytes_out);
  829. result = result.Replace("-", "");
  830. return result;
  831. }
  832. catch (Exception ex)
  833. {
  834. throw new Exception("SHA1加密出错:" + ex.Message);
  835. }
  836. }
  837. #region 获取token
  838. public string getWXToken(string AppId, string AppSecret, bool Cache = true)
  839. {
  840. string token = "";
  841. if (Cache)
  842. {
  843. string time = Function.ReadInstance("/WeChat/TokenTimeSet.txt");
  844. if (!string.IsNullOrEmpty(time))
  845. {
  846. string[] times = time.Split('|');
  847. DateTime date = DateTime.Parse(times[0]);
  848. if (date.AddMinutes(100) > DateTime.Now)
  849. {
  850. token = times[1];
  851. }
  852. }
  853. }
  854. if (string.IsNullOrEmpty(token))
  855. {
  856. string jsonstr = Function.GetWebRequest("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + AppId + "&secret=" + AppSecret);
  857. Function.WriteLog(jsonstr, "获取token");
  858. if (jsonstr.Contains("access_token"))
  859. {
  860. JsonData tokenjson = JsonMapper.ToObject(jsonstr);
  861. string access_token = tokenjson["access_token"].ToString();
  862. if (Cache)
  863. {
  864. Function.WritePage("/WeChat/", "TokenTimeSet.txt", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "|" + access_token);
  865. }
  866. return access_token;
  867. }
  868. }
  869. return token;
  870. }
  871. #endregion
  872. #endregion
  873. }
  874. }