核心代码

  1. HttpClient request = new HttpClient();
  2. byte[] byteRquest = Encoding.GetEncoding("GB18030").GetBytes(sRequestMsg);
  3. ByteArrayContent bytemsg = new ByteArrayContent(byteRquest);
  4. HttpResponseMessage resulthd = await request.PostAsync(sUrl, bytemsg);
  5. Stream result = await resulthd.Content.ReadAsStreamAsync();
  6. StreamReader readerResult = new StreamReader(result, System.Text.Encoding.GetEncoding("GB18030"));
  7. string sResult = await readerResult.ReadToEndAsync();

所有代码

  1. using Blog.Core.Common;
  2. using Blog.Core.Common.Helper;
  3. using Blog.Core.Common.Static;
  4. using Blog.Core.IRepository.Base;
  5. using Blog.Core.IServices;
  6. using Blog.Core.Model;
  7. using Blog.Core.Model.ViewModels;
  8. using Blog.Core.Services.BASE;
  9. using Microsoft.AspNetCore.Http;
  10. using Microsoft.Extensions.Logging;
  11. using System;
  12. using System.Collections.Generic;
  13. using System.IO;
  14. using System.Net.Http;
  15. using System.Text;
  16. using System.Threading;
  17. using System.Threading.Tasks;
  18. namespace Blog.Core.Services
  19. {
  20. public partial class PayServices : BaseServices<RootEntityTkey<int>>, IPayServices
  21. {
  22. IBaseRepository<RootEntityTkey<int>> _dal;
  23. IHttpContextAccessor _httpContextAccessor;
  24. ILogger<PayServices> _logger;
  25. public PayServices(IBaseRepository<RootEntityTkey<int>> dal, ILogger<PayServices> logger, IHttpContextAccessor httpContextAccessor)
  26. {
  27. this._dal = dal;
  28. base.BaseDal = dal;
  29. _logger = logger;
  30. _httpContextAccessor = httpContextAccessor;
  31. }
  32. public async Task<MessageModel<PayReturnResultModel>> Pay(PayNeedModel payModel)
  33. {
  34. _logger.LogInformation("支付开始");
  35. MessageModel<PayReturnResultModel> messageModel = new MessageModel<PayReturnResultModel>();
  36. messageModel.response = new PayReturnResultModel();
  37. string url = string.Empty;
  38. string param = string.Empty;
  39. string returnData = string.Empty;
  40. try
  41. {
  42. _logger.LogInformation($"原始GET参数->{_httpContextAccessor.HttpContext.Request.QueryString}");
  43. //被扫支付
  44. string host = "https://ibsbjstar.ccb.com.cn/CCBIS/B2CMainPlat_00_BEPAY?";
  45. ////商户信息
  46. //string merInfo = "MERCHANTID=105910100190000&POSID=000000000&BRANCHID=610000000";
  47. ////获取柜台完整公钥
  48. //string pubKey = "30819d300d06092a864886f70d010101050003818b0030818702818100a32fb2d51dda418f65ca456431bd2f4173e41a82bb75c2338a6f649f8e9216204838d42e2a028c79cee19144a72b5b46fe6a498367bf4143f959e4f73c9c4f499f68831f8663d6b946ae9fa31c74c9332bebf3cba1a98481533a37ffad944823bd46c305ec560648f1b6bcc64d54d32e213926b26cd10d342f2c61ff5ac2d78b020111";
  49. ////加密原串
  50. //string param = merInfo + "&MERFLAG=1&TERMNO1=&TERMNO2=&ORDERID=937857156" +
  51. // "&QRCODE=134737690209713400&AMOUNT=0.01&TXCODE=PAY100&PROINFO=&REMARK1=&REMARK2=&SMERID=&SMERNAME=&SMERTYPEID=" +
  52. // "&SMERTYPE=&TRADECODE=&TRADENAME=&SMEPROTYPE=&PRONAME=";
  53. Dictionary<string, object> dic = new Dictionary<string, object>();
  54. //支付信息
  55. dic.Add("MERCHANTID", StaticPayInfo.MERCHANTID);// => self::MERCHANTID, // 商户号
  56. dic.Add("POSID", StaticPayInfo.POSID);// => self::POSID, // 柜台号
  57. dic.Add("BRANCHID", StaticPayInfo.BRANCHID);// => self::BRANCHID, // 分行号
  58. dic.Add("TXCODE", "PAY100");// => 'PAY100', // 交易码
  59. dic.Add("MERFLAG", "1");// => '', // 商户类型 1线上 2线下
  60. dic.Add("ORDERID", payModel.ORDERID);//payModel.ORDERID);// => '', // 订单号
  61. dic.Add("QRCODE", payModel.QRCODE);// => '', // 码信息(一维码、二维码)
  62. dic.Add("AMOUNT", payModel.AMOUNT);// => '0.01', // 订单金额,单位:元
  63. dic.Add("PROINFO", payModel.PROINFO);// => '', // 商品名称
  64. dic.Add("REMARK1", payModel.REMARK1);// => '', // 备注 1
  65. dic.Add("REMARK2", payModel.REMARK2);// => '', // 备注 2
  66. //dic.Add("TERMNO1", "");// => '', // 终端编号 1
  67. //dic.Add("TERMNO2", "");// => '', // 终端编号 2
  68. //dic.Add("GROUPMCH", "");// => '', // 集团商户信息
  69. //dic.Add("FZINFO1", "");// => '', // 分账信息一
  70. //dic.Add("FZINFO2", "");// => '', // 分账信息二
  71. //dic.Add("SUB_APPID", "");// => '', // 子商户公众账号 ID
  72. //dic.Add("RETURN_FIELD", "");// => '', // 返回信息位图
  73. //dic.Add("USERPARAM", "");// => '', // 实名支付
  74. //dic.Add("detail", "");// => '', // 商品详情
  75. //dic.Add("goods_tag", "");// => '', // 订单优惠标记
  76. //商户信息
  77. Dictionary<string, object> dicInfo = new Dictionary<string, object>();
  78. dicInfo.Add("MERCHANTID", StaticPayInfo.MERCHANTID);// => self::MERCHANTID, // 商户号
  79. dicInfo.Add("POSID", StaticPayInfo.POSID);// => self::POSID, // 柜台号
  80. dicInfo.Add("BRANCHID", StaticPayInfo.BRANCHID);// => self::BRANCHID, // 分行号
  81. var Info = StringHelper.GetPars(dicInfo);
  82. //获取拼接请求串
  83. param = StringHelper.GetPars(dic);
  84. //加密
  85. var paramEncryption = new CCBPayUtil().makeCCBParam(param, StaticPayInfo.pubKey);
  86. //拼接请求串
  87. url = host + Info + "&ccbParam=" + paramEncryption;
  88. //请求
  89. _logger.LogInformation($"请求地址->{url}");
  90. _logger.LogInformation($"请求参数->{param}");
  91. PayResultModel payResult;
  92. try
  93. {
  94. returnData = await HttpHelper.PostAsync(url);
  95. //转换数据
  96. try
  97. {
  98. payResult = JsonHelper.ParseFormByJson<PayResultModel>(returnData);
  99. }
  100. catch
  101. {
  102. payResult = new PayResultModel { RESULT = "N", ERRMSG = "参数错误", ORDERID = payModel.ORDERID, AMOUNT = payModel.AMOUNT };
  103. returnData = StringHelper.GetCusLine(returnData, 15);
  104. }
  105. _logger.LogInformation($"响应数据->{returnData}");
  106. }
  107. catch (Exception ex)
  108. {
  109. _logger.LogInformation($"异常信息:{ex.Message}");
  110. _logger.LogInformation($"异常堆栈:{ex.StackTrace}");
  111. messageModel = await PayCheck(payModel, 1);
  112. return messageModel;
  113. }
  114. switch (payResult.RESULT)
  115. {
  116. case "Y":
  117. Dictionary<string, object> dicCheckPars = new Dictionary<string, object>();
  118. dicCheckPars.Add("RESULT", payResult.RESULT);
  119. dicCheckPars.Add("ORDERID", payResult.ORDERID);
  120. dicCheckPars.Add("AMOUNT", payResult.AMOUNT);
  121. dicCheckPars.Add("WAITTIME", payResult.WAITTIME);
  122. dicCheckPars.Add("TRACEID", payResult.TRACEID);
  123. string strCheckPars = StringHelper.GetPars(dicCheckPars);
  124. if (NotifyCheck(strCheckPars, payResult.SIGN, StaticPayInfo.pubKey))
  125. {
  126. messageModel.success = true;
  127. messageModel.msg = "支付成功";
  128. }
  129. else
  130. {
  131. messageModel.success = false;
  132. messageModel.msg = "签名失败";
  133. }
  134. break;
  135. case "N":
  136. messageModel.success = false;
  137. messageModel.msg = "支付失败";
  138. break;
  139. case "U":
  140. case "Q":
  141. int waittime = payResult.WAITTIME.ObjToInt();
  142. if (waittime <= 0) waittime = 5;//如果需要等待默认等待5秒后再次查询
  143. Thread.Sleep(waittime * 1000);
  144. //轮询查询
  145. messageModel = await PayCheck(payModel, 1);
  146. break;
  147. default:
  148. messageModel.success = false;
  149. messageModel.msg = "支付失败";
  150. break;
  151. }
  152. messageModel.response.ORDERID = payResult.ORDERID;
  153. messageModel.response.ERRCODE = payResult.ERRCODE;
  154. messageModel.response.ERRMSG = payResult.ERRMSG;
  155. messageModel.response.TRACEID = payResult.TRACEID;
  156. messageModel.response.AMOUNT = payResult.AMOUNT;
  157. messageModel.response.QRCODETYPE = payResult.QRCODETYPE;
  158. }
  159. catch (Exception ex)
  160. {
  161. messageModel.success = false;
  162. messageModel.msg = "服务错误";
  163. messageModel.response.ERRMSG = ex.Message;
  164. _logger.LogInformation($"异常信息:{ex.Message}");
  165. _logger.LogInformation($"异常堆栈:{ex.StackTrace}");
  166. }
  167. finally
  168. {
  169. _logger.LogInformation($"返回数据->{JsonHelper.GetJSON<MessageModel<PayReturnResultModel>>(messageModel)}");
  170. _logger.LogInformation("支付结束");
  171. }
  172. return messageModel;
  173. }
  174. public async Task<MessageModel<PayRefundReturnResultModel>> PayRefund(PayRefundNeedModel payModel)
  175. {
  176. _logger.LogInformation("退款开始");
  177. MessageModel<PayRefundReturnResultModel> messageModel = new MessageModel<PayRefundReturnResultModel>();
  178. messageModel.response = new PayRefundReturnResultModel();
  179. try
  180. {
  181. _logger.LogInformation($"原始GET参数->{_httpContextAccessor.HttpContext.Request.QueryString}");
  182. string REQUEST_SN = StringHelper.GetGuidToLongID().ToString().Substring(0, 16);//请求序列码
  183. string CUST_ID = StaticPayInfo.MERCHANTID;//商户号
  184. string USER_ID = StaticPayInfo.USER_ID;//操作员号
  185. string PASSWORD = StaticPayInfo.PASSWORD;//密码
  186. string TX_CODE = "5W1004";//交易码
  187. string LANGUAGE = "CN";//语言
  188. //string SIGN_INFO = "";//签名信息
  189. //string SIGNCERT = "";//签名CA信息
  190. //外联平台客户端服务部署的地址+设置的监听端口
  191. string sUrl = StaticPayInfo.OutAddress;
  192. //XML请求报文
  193. //string sRequestMsg = $" requestXml=<?xml version=\"1.0\" encoding=\"GB2312\" standalone=\"yes\" ?><TX><REQUEST_SN>{REQUEST_SN}</REQUEST_SN><CUST_ID>{CUST_ID}</CUST_ID><USER_ID>{USER_ID}</USER_ID><PASSWORD>{PASSWORD}</PASSWORD><TX_CODE>{TX_CODE}</TX_CODE><LANGUAGE>{LANGUAGE}</LANGUAGE><TX_INFO><MONEY>{payModel.MONEY}</MONEY><ORDER>{payModel.ORDER}</ORDER><REFUND_CODE>{payModel.REFUND_CODE}</REFUND_CODE></TX_INFO><SIGN_INFO></SIGN_INFO><SIGNCERT></SIGNCERT></TX> ";
  194. string sRequestMsg = $"<?xml version=\"1.0\" encoding=\"GB2312\" standalone=\"yes\" ?><TX><REQUEST_SN>{REQUEST_SN}</REQUEST_SN><CUST_ID>{CUST_ID}</CUST_ID><USER_ID>{USER_ID}</USER_ID><PASSWORD>{PASSWORD}</PASSWORD><TX_CODE>{TX_CODE}</TX_CODE><LANGUAGE>{LANGUAGE}</LANGUAGE><TX_INFO><MONEY>{payModel.MONEY}</MONEY><ORDER>{payModel.ORDER}</ORDER><REFUND_CODE>{payModel.REFUND_CODE}</REFUND_CODE></TX_INFO><SIGN_INFO></SIGN_INFO><SIGNCERT></SIGNCERT></TX> ";
  195. //string sRequestMsg = readRequestFile("E:/02-外联平台/06-测试/测试报文/商户网银/客户端连接-5W1001-W06.txt");
  196. //注意:请求报文必须放在requestXml参数送
  197. sRequestMsg = "requestXml=" + sRequestMsg;
  198. _logger.LogInformation("请求地址:" + sUrl);
  199. _logger.LogInformation("请求报文:" + sRequestMsg);
  200. HttpClient request = new HttpClient();
  201. byte[] byteRquest = Encoding.GetEncoding("GB18030").GetBytes(sRequestMsg);
  202. ByteArrayContent bytemsg = new ByteArrayContent(byteRquest);
  203. HttpResponseMessage resulthd = await request.PostAsync(sUrl, bytemsg);
  204. Stream result = await resulthd.Content.ReadAsStreamAsync();
  205. StreamReader readerResult = new StreamReader(result, System.Text.Encoding.GetEncoding("GB18030"));
  206. string sResult = await readerResult.ReadToEndAsync();
  207. _logger.LogInformation("响应报文:" + sResult);
  208. var Xmlresult = XmlHelper.ParseFormByXml<PayRefundReturnModel>(sResult, "TX");
  209. if (Xmlresult.RETURN_CODE.Equals("000000"))
  210. {
  211. messageModel.success = true;
  212. messageModel.msg = "退款成功";
  213. }
  214. else
  215. {
  216. messageModel.success = false;
  217. messageModel.msg = "退款失败";
  218. }
  219. messageModel.response.RETURN_MSG = Xmlresult.RETURN_MSG;
  220. messageModel.response.TX_CODE = Xmlresult.TX_CODE;
  221. messageModel.response.REQUEST_SN = Xmlresult.REQUEST_SN;
  222. messageModel.response.RETURN_CODE = Xmlresult.RETURN_CODE;
  223. messageModel.response.CUST_ID = Xmlresult.CUST_ID;
  224. messageModel.response.LANGUAGE = Xmlresult.LANGUAGE;
  225. messageModel.response.AMOUNT = Xmlresult.TX_INFO?.AMOUNT;
  226. messageModel.response.PAY_AMOUNT = Xmlresult.TX_INFO?.PAY_AMOUNT;
  227. messageModel.response.ORDER_NUM = Xmlresult.TX_INFO?.ORDER_NUM;
  228. request.Dispose();
  229. }
  230. catch (Exception ex)
  231. {
  232. messageModel.success = false;
  233. messageModel.msg = "服务错误";
  234. messageModel.response.RETURN_MSG = ex.Message;
  235. _logger.LogInformation($"异常信息:{ex.Message}");
  236. _logger.LogInformation($"异常堆栈:{ex.StackTrace}");
  237. }
  238. finally
  239. {
  240. _logger.LogInformation($"返回数据->{JsonHelper.GetJSON<MessageModel<PayRefundReturnResultModel>>(messageModel)}");
  241. _logger.LogInformation("退款结束");
  242. }
  243. return messageModel;
  244. }
  245. public async Task<MessageModel<PayReturnResultModel>> PayCheck(PayNeedModel payModel, int times)
  246. {
  247. _logger.LogInformation("轮询开始");
  248. MessageModel<PayReturnResultModel> messageModel = new MessageModel<PayReturnResultModel>();
  249. messageModel.response = new PayReturnResultModel();
  250. string url = string.Empty;
  251. string param = string.Empty;
  252. string returnData = string.Empty;
  253. try
  254. {
  255. //设置最大轮询次数,跟建行保持一致
  256. int theLastTime = 6;
  257. if (times > theLastTime) throw new Exception($"轮询次数超过最大次数{theLastTime}");
  258. string host = "https://ibsbjstar.ccb.com.cn/CCBIS/B2CMainPlat_00_BEPAY?";
  259. Dictionary<string, object> dic = new Dictionary<string, object>();
  260. dic.Add("MERCHANTID", StaticPayInfo.MERCHANTID);// => self::MERCHANTID, // 商户号
  261. dic.Add("POSID", StaticPayInfo.POSID);// => self::POSID, // 柜台号
  262. dic.Add("BRANCHID", StaticPayInfo.BRANCHID);// => self::BRANCHID, // 分行号
  263. dic.Add("TXCODE", "PAY101");// => 'PAY100', // 交易码
  264. dic.Add("QRYTIME", times.ToString());// => '', // 查询此时(每次加1)
  265. dic.Add("MERFLAG", "1");// => '', // 商户类型
  266. dic.Add("ORDERID", payModel.ORDERID);// => '', // 订单号
  267. dic.Add("QRCODE", payModel.QRCODE);// => '', // 码信息(一维码、二维码)
  268. //dic.Add("GROUPMCH", "");// => '', // 集团商户信息
  269. //dic.Add("QRCODETYPE", "");// => '', // 支付类型1:龙支付 2:微信 3:支付宝 4:银联
  270. //dic.Add("TERMNO1", "");// => '', // 终端编号 1
  271. //dic.Add("TERMNO2", "");// => '', // 终端编号 2
  272. //dic.Add("AMOUNT", "");// => '0.01', // 订单金额,单位:元
  273. //dic.Add("PROINFO", "");// => '', // 商品名称
  274. //dic.Add("REMARK1", "");// => '', // 备注 1
  275. //dic.Add("REMARK2", "");// => '', // 备注 2
  276. //dic.Add("FZINFO1", "");// => '', // 分账信息一
  277. //dic.Add("FZINFO2", "");// => '', // 分账信息二
  278. //dic.Add("SUB_APPID", "");// => '', // 子商户公众账号 ID
  279. //dic.Add("RETURN_FIELD", "");// => '', // 返回信息位图
  280. //dic.Add("USERPARAM", "");// => '', // 实名支付
  281. //dic.Add("detail", "");// => '', // 商品详情
  282. //dic.Add("goods_tag", "");// => '', // 订单优惠标记
  283. //商户信息
  284. Dictionary<string, object> dicInfo = new Dictionary<string, object>();
  285. dicInfo.Add("MERCHANTID", StaticPayInfo.MERCHANTID);// => self::MERCHANTID, // 商户号
  286. dicInfo.Add("POSID", StaticPayInfo.POSID);// => self::POSID, // 柜台号
  287. dicInfo.Add("BRANCHID", StaticPayInfo.BRANCHID);// => self::BRANCHID, // 分行号
  288. var Info = StringHelper.GetPars(dicInfo);
  289. //var newDic = dic.OrderBy(t => t.Key).ToDictionary(o => o.Key, p => p.Value);
  290. //参数信息
  291. param = StringHelper.GetPars(dic);
  292. //加密
  293. var paramEncryption = new CCBPayUtil().makeCCBParam(param, StaticPayInfo.pubKey);
  294. //拼接请求串
  295. url = host + Info + "&ccbParam=" + paramEncryption;
  296. //请求
  297. _logger.LogInformation($"请求地址->{url}");
  298. _logger.LogInformation($"请求参数->{param}");
  299. //转换数据
  300. PayResultModel payResult;
  301. try
  302. {
  303. returnData = await HttpHelper.PostAsync(url);
  304. _logger.LogInformation($"响应数据->{returnData}");
  305. }
  306. catch (Exception ex)
  307. {
  308. _logger.LogInformation($"异常信息:{ex.Message}");
  309. _logger.LogInformation($"异常堆栈:{ex.StackTrace}");
  310. return await PayCheck(payModel, ++times);
  311. }
  312. try
  313. {
  314. payResult = JsonHelper.ParseFormByJson<PayResultModel>(returnData);
  315. }
  316. catch
  317. {
  318. payResult = new PayResultModel { RESULT = "N", ERRMSG = "参数错误", ORDERID = payModel.ORDERID, AMOUNT = payModel.AMOUNT };
  319. }
  320. switch (payResult.RESULT)
  321. {
  322. case "Y":
  323. Dictionary<string, object> dicCheckPars = new Dictionary<string, object>();
  324. dicCheckPars.Add("RESULT", payResult.RESULT);
  325. dicCheckPars.Add("ORDERID", payResult.ORDERID);
  326. dicCheckPars.Add("AMOUNT", payResult.AMOUNT);
  327. dicCheckPars.Add("WAITTIME", payResult.WAITTIME);
  328. string strCheckPars = StringHelper.GetPars(dicCheckPars);
  329. if (NotifyCheck(strCheckPars, payResult.SIGN, StaticPayInfo.pubKey))
  330. {
  331. messageModel.success = true;
  332. messageModel.msg = "支付成功";
  333. }
  334. else
  335. {
  336. messageModel.success = false;
  337. messageModel.msg = "签名失败";
  338. }
  339. break;
  340. case "N":
  341. messageModel.success = false;
  342. messageModel.msg = "支付失败";
  343. break;
  344. case "U":
  345. case "Q":
  346. int waittime = payResult.WAITTIME.ObjToInt();
  347. if (waittime <= 0) waittime = 5;//如果需要等待默认等待5秒后再次查询
  348. Thread.Sleep(waittime * 1000);
  349. //改成轮询查询
  350. messageModel = await PayCheck(payModel, ++times);
  351. break;
  352. default:
  353. messageModel.success = false;
  354. messageModel.msg = "支付失败";
  355. break;
  356. }
  357. messageModel.response.ORDERID = payResult.ORDERID;
  358. messageModel.response.ERRCODE = payResult.ERRCODE;
  359. messageModel.response.ERRMSG = payResult.ERRMSG;
  360. messageModel.response.TRACEID = payResult.TRACEID;
  361. messageModel.response.AMOUNT = payResult.AMOUNT;
  362. messageModel.response.QRCODETYPE = payResult.QRCODETYPE;
  363. }
  364. catch (Exception ex)
  365. {
  366. messageModel.success = false;
  367. messageModel.msg = "服务错误";
  368. messageModel.response.ERRMSG = ex.Message;
  369. _logger.LogInformation($"异常信息:{ex.Message}");
  370. _logger.LogInformation($"异常堆栈:{ex.StackTrace}");
  371. }
  372. finally
  373. {
  374. _logger.LogInformation($"返回数据->{JsonHelper.GetJSON<MessageModel<PayReturnResultModel>>(messageModel)}");
  375. _logger.LogInformation("轮序结束");
  376. }
  377. return messageModel;
  378. }
  379. public bool NotifyCheck(string strSrc, string sign, string pubKey)
  380. {
  381. return new CCBPayUtil().verifyNotifySign(strSrc, sign, pubKey);
  382. }
  383. }
  384. }