c# 微信jsapi支付

ps:接着之前的完成了微信授权获取用户的基础信息外

微信支付也需要快速完成,支付的确很多坑,大多数是不认真阅读开发文档导致

stemp1 :发起预支付api

此处遇到的坑是,由于需求中的信息,例如公众号下对应一个商户号,但是需求文档中给的商户号是错误的,不是这个公众号对应下的商户号,

直接被返回 公众号与商户号不一致!!!,此时经历了寻找好几个部门的人,终于找到了对应的商户号!然而已经懵逼了好久….

#region 扫码进行打赏操作
        /// 
        /// HttpPost   
        /// api/Appraise/ScanToAward
        /// 打赏
        /// 
        /// 
        [HttpPost]
        [ActionName("ScanToAward")]
        public IHttpActionResult ScanToAward(ScanToAwardModel model)
        {
            string scan_notify_url = "你的回调地址";
            try
            {
                if (model == null)
                {
                    throw new CustomException("操作失败,无效参数");
                }

                if (string.IsNullOrEmpty(model.totle_fee))
                {
                    throw new CustomException("操作失败,无效打赏金额");
                }

                //if (string.IsNullOrEmpty(model.UserId))
                //{
                //    throw new CustomException("操作失败,无效顾客信息");
                //}
                string prepay_id = "";
                int crid = model.CID.ToIntForPage();
                int uid = model.UserId.ToIntForPage();
                decimal totalfee = model.totle_fee.ToDecimal();
                DateTime now = DateTime.Now;
                //数据库操作,省略*******
                weixin_payment payment = new weixin_payment
                {
                    appid = "",
                    mchid = "",
                    CID = cid,
                    body = "扫码打赏",
                    Name = cr.Name,
                    itime = now,
                    openid = userUserID.openid,
                    out_trade_no = "wx" + DateTime.Now.ToString("yyyyMMddHHmmssfff"),
                    scene_info = "扫码打赏",
                    SName = SpName,
                    UserId = uid,
                    notify_url = scan_notify_url,
                    total_fee = totalfee,
                };
                dbo.weixin_payment.Add(payment);
                int r = dbo.SaveChanges();
                if (r > 0)
                {
                    string temp = WechatService.WechatPrePayScan(payment.body, payment, "JSAPI", "127.0.0.1", out prepay_id);
                    return Json(Success(temp.Replace("\\", "")));
                }
                else
                {
                    return Json(getException("打赏失败"));
                }

            }
            catch (CustomException ce)
            {
              // 数据库操作
                return Json(getException(ce.Message));
            }
            catch (Exception ex)
            {
              // 数据库操作
                return Json(getException(ex));
            }
        }
        #endregion

stemp2 预支付主要函数,主要是进行签名,参数一定到正确,如下:

/// 
        /// 执行微信预支付
        /// 
        /// 产品描述
        /// 订单编号
        /// 
        public static string WechatPrePayScan(string gooddesc, mf_weixin_payment pay, string tradetype, string userip, out string prepay_id, string type = "buyerorder")
        {
            memberEntities dbo = new memberEntities();
            decimal Patment = 0;//支付金额
            string appid = Appid;//微信公众号Appid
            string mchid = much_id;//微信支付商户号
            string UserOpenid = "";//用户openid,JSAPI微信支付要用
            byte[] goodsdescByte = System.Text.Encoding.Default.GetBytes(gooddesc);
            gooddesc = goodsdescByte.Length >= 30 ? System.Text.Encoding.Default.GetString(goodsdescByte, 0, 30) : gooddesc;
            switch (type)
            {
                case "buyerorder":
                    //操作数据库***
                    Patment = pay.total_fee;
                    if (tradetype == "JSAPI")
                    {
                        //获取订单用户openid 
                        UserOpenid = pay.openid;
                     }
                    break;
                case "rechargeorder":
                    //操作数据库***
                    Patment = pay.total_fee;
                    break;
                default:
                    throw new CustomException("传入类型出错。");
            }
            //Patment = 1;
            //微信接口价格是按“分”来计算的,且不能有小数点
            int payment = Convert.ToInt32(Patment * 100);
            //随机字符串
            string nonce_str = Md5Hash(RandomNumber(10, true)).ToUpper();
            //微信支付的订单号
            string WxPayOrderSN = pay.out_trade_no;

            //签名
            SortedDictionary<string, string> SignParamsObj = new SortedDictionary<string, string>();
            SignParamsObj.Add("appid", appid);
            SignParamsObj.Add("body", gooddesc);
            SignParamsObj.Add("mch_id", mchid);
            SignParamsObj.Add("nonce_str", nonce_str);
            SignParamsObj.Add("notify_url", pay.notify_url);
            SignParamsObj.Add("out_trade_no", pay.out_trade_no);
            if (tradetype == "JSAPI")
            {
                if (string.IsNullOrEmpty(UserOpenid))
                    throw new CustomException("网页支付必须绑定微信。");
                else SignParamsObj.Add("openid", pay.openid);
            }
            SignParamsObj.Add("spbill_create_ip", userip);
            SignParamsObj.Add("total_fee", payment.ToString());
            SignParamsObj.Add("trade_type", tradetype);
            //签名  方法1 
            string stringA = wechatService.MakeSignStr(SignParamsObj);
            string sign = MD5Encrypt32(stringA + "&key=" + Key);

            //string stringA = "appid=" + appid + "&body="
            //     + gooddesc + "&mch_id=" + mchid + "&nonce_str="
            //     + nonce_str + "¬ify_url=http://package.mfsj.cn&out_trade_no="
            //     + ID + "&openid=" + UserOpenid + "&spbill_create_ip=8.8.8.8&total_fee="
            //     + payment + "&trade_type=JSAPI";

            //传入数据为XML格式
            string data = ""
                          + "{7}"
                          + "{6}"
                          + "{0}"
                          + "{1}"
                          + "{2}"
                          + "{3}"
                          + "{4}"
                          + "{9}"
                          + "{5}"
                          + "{8}";
            if (!string.IsNullOrEmpty(UserOpenid))
            {
                data += "" + UserOpenid + "";
            }
            data += "";

            data = string.Format(
                data,
                nonce_str,
                sign,
                pay.notify_url,
                WxPayOrderSN,
                payment,
                NOTIFY_URL,
                mchid,
                appid,
                tradetype,
                userip);

            //执行请求
            string result = MethodHelper.RequestUrlByPOST("https://api.mch.weixin.qq.com/pay/unifiedorder", data);
            //将返回结果转换成json字符串输出
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(result);
            string jsonresult = JsonConvert.SerializeXmlNode(doc);
            jsonresult = jsonresult.Replace("#", "");
            jsonresult = jsonresult.Replace("cdata-section", "cdata");
            if (tradetype == "JSAPI")
            {
                return JsonConvert.SerializeObject(GetWechatJSSDKPayMsg(jsonresult, out prepay_id));
            }
            else
            {
                return JsonConvert.SerializeObject(GetWechatJSSDKPayMsg(jsonresult, out prepay_id));
            }
        }

经常报签名错误的原因有一下几个:http://jingyan.baidu.com/article/59703552c3c9808fc1074072.html 百度说得很多了

但是我们真的遇到了

1 key真的不对!公众平台的密钥和商户号的密钥是不一样的!!!微信支付审核成功之后会收到一封邮件,邮件中有appid 商户号,商户后台登录上号和密码,登录到商户后台:账户设置-安全设置-切换到API安全,下载证书,下面有一个api密匙,进去填写一个字符串 ,保存,后续两次签名都是用的这个手动设置的key!!!后来重新生成一个了;

2 openid要正确

3 金额分要注意,单位是用分的

4 仔细阅读文档后,就很少出错了

以下解释发起微信支付成功后的数据,返回响应wx的json给前台

后台如下:

/// 
        /// 获取微信JSSDK支付调起所需要的信息
        /// 
        /// 
        public static WechatJSSDKPayMessageModel GetWechatJSSDKPayMsg(string prepayresult, out string prepay_id)
        {
            //返回结果对象
            WechatJSSDKPayMessageModel Result = new WechatJSSDKPayMessageModel();
            //支付签名排序字典
            SortedDictionary<string, string> SignParams = new SortedDictionary<string, string>();
            //分析微信预支付返回结果,并取出预支付Id
            JObject PrepayObj = (JObject)JsonConvert.DeserializeObject(prepayresult);
            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)
            {
                //return.getException(prepayresult);
                throw new CustomException("微信预支付信息有误。");
            }
            if (PrepayObj["xml"]["return_code"]["cdata"].ToString().ToUpper() != "SUCCESS" || PrepayObj["xml"]["result_code"]["cdata"].ToString().ToUpper() != "SUCCESS")
            {
                //JsonReturn.getException(prepayresult);
                throw new CustomException("微信预支付有误。");
            }
            //时间戳
            Result.timeStamp = CreatenTimestamp().ToString();
            //随机字符串
            Result.nonceStr = Md5Hash(RandomNumber(10, true)).ToUpper();
            //package
            Result.package = "prepay_id=" + PrepayObj["xml"]["prepay_id"]["cdata"].ToString();
            Result.prepay_id = PrepayObj["xml"]["prepay_id"]["cdata"].ToString();
            Result.appId = Appid;
            //把微信支付签名所需要的参数放入字典
            SignParams.Add("appId", Appid);
            SignParams.Add("timeStamp", Result.timeStamp);
            SignParams.Add("nonceStr", Result.nonceStr);
            SignParams.Add("package", Result.package);
            SignParams.Add("signType", "MD5");
            //生成签名
            string WxPaySign = wechatService.MakeSignStr(SignParams);
            WxPaySign += "&key=" + Key;
            Result.paysign = Md5Hash(WxPaySign).ToUpper();
            prepay_id = Result.prepay_id;
            return Result;
        }

前台如下:

//angular 打赏控制器
.controller('rewardCtrl', function ($scope, Utils, $ionicPopup, $ionicLoading, $http) {
        $scope.referenceInfo = JSON.parse(window.sessionStorage.getItem('comment'));
        console.log($scope.referenceInfo);
        //各个金额等级
        $scope.rewardMoney = [{money: 1}, {money: 3}, {money: 5}, {money: 7}, {money: 10}, {money: 20}];
        $scope.importMoney = {};//其他金额
        var myPopup;
        $scope.isOK = function (reward) {
            var sendData = {
                BookId: $scope.referenceInfo.BookId,
                d_fromID: $scope.referenceInfo.UserId,
                d_totle_fee: reward,
                CounselorId: $scope.referenceInfo.CounselorID
            };
            console.log(sendData);
            $http({method: 'POST', url: API_URL + 'Appraise/AddAppraiseAward', data: sendData}).then(function (res) {
                var temp = JSON.parse(res.data.info);
                //console.log(temp);
                //微信窗口
                wx.chooseWXPay({
                    timestamp: temp.timeStamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
                    nonceStr: temp.nonceStr, // 支付签名随机串,不长于 32 位
                    package: temp.package, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***)
                    signType: 'MD5', // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
                    paySign: temp.paysign, // 支付签名
                    success: function (res) {
                        // 支付成功后的回调函数
                        console.log(res)
                    }
                });
            });
        };

        //弹框其他金额打赏
        $scope.inputMoney = function () {
            myPopup = $ionicPopup.show({
                templateUrl: 'templates/reference/reward-popup.html',
                scope: $scope
            })
        };
        //确定其他输入金额打赏
        $scope.otherReward = function () {
            //判断输入的金额是否符合
            if ($scope.importMoney.value === undefined || $scope.importMoney.value === '' || $scope.importMoney.value === null) {
                $ionicLoading.show({
                    template: '请输入数字',
                    duration: 1000
                });
            }
            $scope.isOK($scope.importMoney.value);
            myPopup.close()
        };
        //关闭其他金额打赏
        $scope.closePopup = function () {
            myPopup.close()
        };
    });

stemp3 回调

刚开始的时候回调地址需要在公众号那边直接填写的,不填写永远也收不到回调

#region 微信回调主控制器
        /// 
        /// HttpPost      WechatResponseModel wechat
        /// 微信回调主控制器 回调
        /// 
        /// 
        /// 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支付就基本上完成。扫码支付需要使用到证书,其应用场景更多,将在后面的文中补上

你可能感兴趣的:(c#,.Net,微信开发,项目例子,微信,支付,api)