c# 微信支付
ps:接着之前的完成了微信授权获取用户的基础信息外
微信支付也需要快速完成,支付的确很多坑,大多数是不认真阅读开发文档导致
stemp1 :发起预支付api
此处遇到的坑是,由于需求中的信息,例如公众号下对应一个商户号,但是需求文档中给的商户号是错误的,不是这个公众号对应下的商户号,
直接被返回 公众号与商户号不一致!!!,此时经历了寻找好几个部门的人,终于找到了对应的商户号!然而已经懵逼了好久....
1 #region 扫码进行打赏操作 2 /// <summary> 3 /// HttpPost 4 /// api/Appraise/ScanToAward 5 /// 打赏 6 /// </summary> 7 /// <returns></returns> 8 [HttpPost] 9 [ActionName("ScanToAward")] 10 public IHttpActionResult ScanToAward(ScanToAwardModel model) 11 { 12 string scan_notify_url = "你的回调地址"; 13 try 14 { 15 if (model == null) 16 { 17 throw new CustomException("操作失败,无效参数"); 18 } 19 20 if (string.IsNullOrEmpty(model.totle_fee)) 21 { 22 throw new CustomException("操作失败,无效打赏金额"); 23 } 24 25 //if (string.IsNullOrEmpty(model.UserId)) 26 //{ 27 // throw new CustomException("操作失败,无效顾客信息"); 28 //} 29 string prepay_id = ""; 30 int crid = model.CID.ToIntForPage(); 31 int uid = model.UserId.ToIntForPage(); 32 decimal totalfee = model.totle_fee.ToDecimal(); 33 DateTime now = DateTime.Now; 34 //数据库操作,省略******* 35 weixin_payment payment = new weixin_payment 36 { 37 appid = "", 38 mchid = "", 39 CID = cid, 40 body = "扫码打赏", 41 Name = cr.Name, 42 itime = now, 43 openid = userUserID.openid, 44 out_trade_no = "wx" + DateTime.Now.ToString("yyyyMMddHHmmssfff"), 45 scene_info = "扫码打赏", 46 SName = SpName, 47 UserId = uid, 48 notify_url = scan_notify_url, 49 total_fee = totalfee, 50 }; 51 dbo.weixin_payment.Add(payment); 52 int r = dbo.SaveChanges(); 53 if (r > 0) 54 { 55 string temp = WechatService.WechatPrePayScan(payment.body, payment, "JSAPI", "127.0.0.1", out prepay_id); 56 return Json(Success(temp.Replace("\\", ""))); 57 } 58 else 59 { 60 return Json(getException("打赏失败")); 61 } 62 63 } 64 catch (CustomException ce) 65 { 66 // 数据库操作 67 return Json(getException(ce.Message)); 68 } 69 catch (Exception ex) 70 { 71 // 数据库操作 72 return Json(getException(ex)); 73 } 74 } 75 #endregion
stemp2 预支付主要函数,主要是进行签名,参数一定到正确,如下:
1 /// <summary> 2 /// 执行微信预支付 3 /// </summary> 4 /// <param name="gooddesc">产品描述</param> 5 /// <param name="orderno">订单编号</param> 6 /// <returns></returns> 7 public static string WechatPrePayScan(string gooddesc, mf_weixin_payment pay, string tradetype, string userip, out string prepay_id, string type = "buyerorder") 8 { 9 memberEntities dbo = new memberEntities(); 10 decimal Patment = 0;//支付金额 11 string appid = Appid;//微信公众号Appid 12 string mchid = much_id;//微信支付商户号 13 string UserOpenid = "";//用户openid,JSAPI微信支付要用 14 byte[] goodsdescByte = System.Text.Encoding.Default.GetBytes(gooddesc); 15 gooddesc = goodsdescByte.Length >= 30 ? System.Text.Encoding.Default.GetString(goodsdescByte, 0, 30) : gooddesc; 16 switch (type) 17 { 18 case "buyerorder": 19 //操作数据库*** 20 Patment = pay.total_fee; 21 if (tradetype == "JSAPI") 22 { 23 //获取订单用户openid 24 UserOpenid = pay.openid; 25 } 26 break; 27 case "rechargeorder": 28 //操作数据库*** 29 Patment = pay.total_fee; 30 break; 31 default: 32 throw new CustomException("传入类型出错。"); 33 } 34 //Patment = 1; 35 //微信接口价格是按“分”来计算的,且不能有小数点 36 int payment = Convert.ToInt32(Patment * 100); 37 //随机字符串 38 string nonce_str = Md5Hash(RandomNumber(10, true)).ToUpper(); 39 //微信支付的订单号 40 string WxPayOrderSN = pay.out_trade_no; 41 42 //签名 43 SortedDictionary<string, string> SignParamsObj = new SortedDictionary<string, string>(); 44 SignParamsObj.Add("appid", appid); 45 SignParamsObj.Add("body", gooddesc); 46 SignParamsObj.Add("mch_id", mchid); 47 SignParamsObj.Add("nonce_str", nonce_str); 48 SignParamsObj.Add("notify_url", pay.notify_url); 49 SignParamsObj.Add("out_trade_no", pay.out_trade_no); 50 if (tradetype == "JSAPI") 51 { 52 if (string.IsNullOrEmpty(UserOpenid)) 53 throw new CustomException("网页支付必须绑定微信。"); 54 else SignParamsObj.Add("openid", pay.openid); 55 } 56 SignParamsObj.Add("spbill_create_ip", userip); 57 SignParamsObj.Add("total_fee", payment.ToString()); 58 SignParamsObj.Add("trade_type", tradetype); 59 //签名 方法1 60 string stringA = wechatService.MakeSignStr(SignParamsObj); 61 string sign = MD5Encrypt32(stringA + "&key=" + Key); 62 63 //string stringA = "appid=" + appid + "&body=" 64 // + gooddesc + "&mch_id=" + mchid + "&nonce_str=" 65 // + nonce_str + "¬ify_url=http://package.mfsj.cn&out_trade_no=" 66 // + ID + "&openid=" + UserOpenid + "&spbill_create_ip=8.8.8.8&total_fee=" 67 // + payment + "&trade_type=JSAPI"; 68 69 //传入数据为XML格式 70 string data = "<xml>" 71 + "<appid>{7}</appid>" 72 + "<mch_id>{6}</mch_id>" 73 + "<nonce_str>{0}</nonce_str>" 74 + "<sign>{1}</sign>" 75 + "<body>{2}</body>" 76 + "<out_trade_no>{3}</out_trade_no>" 77 + "<total_fee>{4}</total_fee>" 78 + "<spbill_create_ip>{9}</spbill_create_ip>" 79 + "<notify_url>{5}</notify_url>" 80 + "<trade_type>{8}</trade_type>"; 81 if (!string.IsNullOrEmpty(UserOpenid)) 82 { 83 data += "<openid>" + UserOpenid + "</openid>"; 84 } 85 data += "</xml>"; 86 87 data = string.Format( 88 data, 89 nonce_str, 90 sign, 91 pay.notify_url, 92 WxPayOrderSN, 93 payment, 94 NOTIFY_URL, 95 mchid, 96 appid, 97 tradetype, 98 userip); 99 100 //执行请求 101 string result = MethodHelper.RequestUrlByPOST("https://api.mch.weixin.qq.com/pay/unifiedorder", data); 102 //将返回结果转换成json字符串输出 103 XmlDocument doc = new XmlDocument(); 104 doc.LoadXml(result); 105 string jsonresult = JsonConvert.SerializeXmlNode(doc); 106 jsonresult = jsonresult.Replace("#", ""); 107 jsonresult = jsonresult.Replace("cdata-section", "cdata"); 108 if (tradetype == "JSAPI") 109 { 110 return JsonConvert.SerializeObject(GetWechatJSSDKPayMsg(jsonresult, out prepay_id)); 111 } 112 else 113 { 114 return JsonConvert.SerializeObject(GetWechatJSSDKPayMsg(jsonresult, out prepay_id)); 115 } 116 }
经常报签名错误的原因有一下几个:http://jingyan.baidu.com/article/59703552c3c9808fc1074072.html 百度说得很多了
但是我们真的遇到了
1 key真的不对!公众平台的密钥和商户号的密钥是不一样的!!!微信支付审核成功之后会收到一封邮件,邮件中有appid 商户号,商户后台登录上号和密码,登录到商户后台:账户设置-安全设置-切换到API安全,下载证书,下面有一个api密匙,进去填写一个字符串 ,保存,后续两次签名都是用的这个手动设置的key!!!后来重新生成一个了;
2 openid要正确
3 金额分要注意,单位是用分的
4 仔细阅读文档后,就很少出错了
以下解释发起微信支付成功后的数据,返回响应wx的json给前台
后台如下:
1 /// <summary> 2 /// 获取微信JSSDK支付调起所需要的信息 3 /// </summary> 4 /// <returns></returns> 5 public static WechatJSSDKPayMessageModel GetWechatJSSDKPayMsg(string prepayresult, out string prepay_id) 6 { 7 //返回结果对象 8 WechatJSSDKPayMessageModel Result = new WechatJSSDKPayMessageModel(); 9 //支付签名排序字典 10 SortedDictionary<string, string> SignParams = new SortedDictionary<string, string>(); 11 //分析微信预支付返回结果,并取出预支付Id 12 JObject PrepayObj = (JObject)JsonConvert.DeserializeObject(prepayresult); 13 if (PrepayObj == null || PrepayObj["xml"] == null || PrepayObj["xml"]["return_code"] == null || PrepayObj["xml"]["return_code"]["cdata"] == null || PrepayObj["xml"]["result_code"] == null || PrepayObj["xml"]["result_code"]["cdata"] == null || PrepayObj["xml"]["return_msg"] == null || PrepayObj["xml"]["return_msg"]["cdata"] == null) 14 { 15 //return.getException(prepayresult); 16 throw new CustomException("微信预支付信息有误。"); 17 } 18 if (PrepayObj["xml"]["return_code"]["cdata"].ToString().ToUpper() != "SUCCESS" || PrepayObj["xml"]["result_code"]["cdata"].ToString().ToUpper() != "SUCCESS") 19 { 20 //JsonReturn.getException(prepayresult); 21 throw new CustomException("微信预支付有误。"); 22 } 23 //时间戳 24 Result.timeStamp = CreatenTimestamp().ToString(); 25 //随机字符串 26 Result.nonceStr = Md5Hash(RandomNumber(10, true)).ToUpper(); 27 //package 28 Result.package = "prepay_id=" + PrepayObj["xml"]["prepay_id"]["cdata"].ToString(); 29 Result.prepay_id = PrepayObj["xml"]["prepay_id"]["cdata"].ToString(); 30 Result.appId = Appid; 31 //把微信支付签名所需要的参数放入字典 32 SignParams.Add("appId", Appid); 33 SignParams.Add("timeStamp", Result.timeStamp); 34 SignParams.Add("nonceStr", Result.nonceStr); 35 SignParams.Add("package", Result.package); 36 SignParams.Add("signType", "MD5"); 37 //生成签名 38 string WxPaySign = wechatService.MakeSignStr(SignParams); 39 WxPaySign += "&key=" + Key; 40 Result.paysign = Md5Hash(WxPaySign).ToUpper(); 41 prepay_id = Result.prepay_id; 42 return Result; 43 }
前台如下:
1 //angular 打赏控制器 2 .controller('rewardCtrl', function ($scope, Utils, $ionicPopup, $ionicLoading, $http) { 3 $scope.referenceInfo = JSON.parse(window.sessionStorage.getItem('comment')); 4 console.log($scope.referenceInfo); 5 //各个金额等级 6 $scope.rewardMoney = [{money: 1}, {money: 3}, {money: 5}, {money: 7}, {money: 10}, {money: 20}]; 7 $scope.importMoney = {};//其他金额 8 var myPopup; 9 $scope.isOK = function (reward) { 10 var sendData = { 11 BookId: $scope.referenceInfo.BookId, 12 d_fromID: $scope.referenceInfo.UserId, 13 d_totle_fee: reward, 14 CounselorId: $scope.referenceInfo.CounselorID 15 }; 16 console.log(sendData); 17 $http({method: 'POST', url: API_URL + 'Appraise/AddAppraiseAward', data: sendData}).then(function (res) { 18 var temp = JSON.parse(res.data.info); 19 //console.log(temp); 20 //微信窗口 21 wx.chooseWXPay({ 22 timestamp: temp.timeStamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符 23 nonceStr: temp.nonceStr, // 支付签名随机串,不长于 32 位 24 package: temp.package, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***) 25 signType: 'MD5', // 签名方式,默认为'SHA1',使用新版支付需传入'MD5' 26 paySign: temp.paysign, // 支付签名 27 success: function (res) { 28 // 支付成功后的回调函数 29 console.log(res) 30 } 31 }); 32 }); 33 }; 34 35 //弹框其他金额打赏 36 $scope.inputMoney = function () { 37 myPopup = $ionicPopup.show({ 38 templateUrl: 'templates/reference/reward-popup.html', 39 scope: $scope 40 }) 41 }; 42 //确定其他输入金额打赏 43 $scope.otherReward = function () { 44 //判断输入的金额是否符合 45 if ($scope.importMoney.value === undefined || $scope.importMoney.value === '' || $scope.importMoney.value === null) { 46 $ionicLoading.show({ 47 template: '请输入数字', 48 duration: 1000 49 }); 50 } 51 $scope.isOK($scope.importMoney.value); 52 myPopup.close() 53 }; 54 //关闭其他金额打赏 55 $scope.closePopup = function () { 56 myPopup.close() 57 }; 58 });
stemp3 回调
刚开始的时候回调地址需要在公众号那边直接填写的,不填写永远也收不到回调
#region 微信回调主控制器 /// <summary> /// HttpPost WechatResponseModel wechat /// 微信回调主控制器 回调 /// </summary> /// <returns></returns> /// api/WeChat/ResultNotifyController [HttpPost] [ActionName("ResultNotifyController")] public IHttpActionResult ResultNotifyController() { //一开始的时候做一个监控,看看有没有成功回调 Log4NetInfo.LogInfo("微信支付回调进入页面"); string resultFromWx = getPostStr(); var res = XDocument.Parse(resultFromWx); //通信成功 if (res.Element("xml").Element("return_code").Value == "SUCCESS") { if (res.Element("xml").Element("result_code").Value == "SUCCESS") { string ordecode = res.Element("xml").Element("out_trade_no").Value; var appraise = dbo.mf_appraise.Where(c => c.OrderId == ordecode).FirstOrDefault(); try { //操作数据库; dbo.Entry(appraise).State = System.Data.Entity.EntityState.Modified; int r = dbo.SaveChanges(); } catch (Exception ex) { //操作数据库; int r = dbo.SaveChanges(); } return Json(new { return_code = "SUCCESS", return_msg = "OK" }); } else { //操作数据库; dbo.Entry(appraise).State = System.Data.Entity.EntityState.Modified; int r = dbo.SaveChanges(); } } else { //操作数据库; int r = dbo.SaveChanges(); } Log4NetInfo.LogInfo("微信支付回调退出页面"); return Json(new { return_code = "", return_msg = "" }); } //获得Post过来的数据 这里接收采摘网友的源码,因为快速开发,只能用现成的了。而且这个获取字节流的形式,试过了一般的方法拿不到回调的数据 public string getPostStr() { Int32 intLen = Convert.ToInt32(HttpContext.Current.Request.InputStream.Length); byte[] b = new byte[intLen]; HttpContext.Current.Request.InputStream.Read(b, 0, intLen); return System.Text.Encoding.UTF8.GetString(b); }
到这里,微信jsapi支付就基本上完成。扫码支付需要使用到证书,其应用场景更多,将在后面的文中补上
madamadanie

浙公网安备 33010602011771号