偷影子的人

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
View Code

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 + "&notify_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         }
View Code

经常报签名错误的原因有一下几个: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         }
View Code

前台如下:

 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     });
View Code

 

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);
        }
View Code

到这里,微信jsapi支付就基本上完成。扫码支付需要使用到证书,其应用场景更多,将在后面的文中补上

 

posted @ 2017-07-20 20:54  肉!快到碗里来  阅读(246)  评论(0)    收藏  举报