C# 微信支付JSAPI开发注意事项

最近在做微信支付项目,记录一下:
1、需要现在微信公众平台上设置,具体在 菜单:设置-公众号设置-功能设置,把开发程序所在的域名增加,具体在业务域名、JS接口安全域名
、网页授权域名(这个主要是用于授权用的) 都要增加相应的域名目录。
2、在微信支付平台,产品中心-开发配置-支付设置,公众号支付-JSAPI授权目录增加域名目录,否则不能成功调用。 以上两步必须同时设置好。
3、然后阅读开发微信支付开发文档,根据文档开发即可。虽然大家都说有很多坑,但是慢慢解决,能够很好的实现调用。自己感觉微信支付比支付宝支付要简单。如果还是无法成功,或者提示签名错误,有的时候需要重置API密钥试试(调试了几天 找了好多办法都没有解决,结果最后真的重置了API密钥就好了)。
4、还有一个问题,就是微信调起支付后,没有支付,然后再支付的时候提示重复下单或这缺少total_fee参数(这个实际上有的时候并不是真少这个参数),这个时候应该是body内容不一样但是订单号一样。
我的解决办法是这样的:每次调起支付的时候,将生成的支付信息保存到数据库,如果当时调起支付未支付,那么再次调起的时候会先搜索一下数据库,如果有这条记录,那么将当时的timestamp、NonceStr、paysign、Prepay_id等信息提取出来,生成支付数据。如果数据库没有数据,则启用新的支付参数。这样就能保证统一支付下单的是一致的,不至于重复下单。在这里插入代码片

几个关键代码参考:


	 public class UnifiedOrder
    {
        /// <summary>

        /// <summary>
        /// 微信支付分配的终端设备号
        /// </summary>
        public string _device_info = ""; /// <summary>
        /// 公共号ID(微信分配的公众账号 ID)
        /// </summary>
        public string appid = "";
        /// <summary>
        /// 商户号(微信支付分配的商户号)
        /// </summary>
        public string mch_id = "";
        /// <summary>
        /// 微信支付分配的终端设备号
        /// </summary>
        public string device_info = "";
        /// <summary>
        /// 随机字符串,不长于 32 位
        /// </summary>
        public string nonce_str = "";
        /// <summary>
        /// 签名
        /// </summary>
        public string sign = "";
        /// <summary>
        /// 商品描述
        /// </summary>
        public string body = "";
        /// <summary>
        /// 附加数据,原样返回
        /// </summary>
        public string attach = "";
        /// <summary>
        /// 商户系统内部的订单号,32个字符内、可包含字母,确保在商户系统唯一,详细说明
        /// </summary>
        public string out_trade_no = "";
        /// <summary>
        /// 订单总金额,单位为分,不能带小数点
        /// </summary>
        public int total_fee = 0;
        /// <summary>
        /// 终端IP
        /// </summary>
        public string spbill_create_ip = "";
        /// <summary>
        /// 订 单 生 成 时 间 , 格 式 为yyyyMMddHHmmss,如 2009 年12 月 25 日 9 点 10 分 10 秒表示为 20091225091010。时区为 GMT+8 beijing。该时间取自商户服务器
        /// </summary>
        public string time_start = "";
        /// <summary>
        /// 交易结束时间
        /// </summary>
        public string time_expire = "";
        /// <summary>
        /// 商品标记 商品标记,该字段不能随便填,不使用请填空,使用说明详见第 5 节
        /// </summary>
        public string goods_tag = "";
        /// <summary>
        /// 接收微信支付成功通知
        /// </summary>
        public string notify_url = "";
        /// <summary>
        /// JSAPI、NATIVE、APP
        /// </summary>
        public string trade_type = "";
        /// <summary>
        /// 用户标识 trade_type 为 JSAPI时,此参数必传
        /// </summary>
        public string openid = "";
        /// <summary>
        /// 只在 trade_type 为 NATIVE时需要填写。
        /// </summary>
        public string product_id = "";
 
     }

这个是主要的代码

// <summary>
///TenpayUtil 的摘要说明
/// </summary>
public class TenpayUtil
{
    public TenpayUtil()
    {
        //
      
    }


    //TODO: 在此处添加构造函数逻辑
    //
    /// <summary>
    /// 统一支付接口
    /// </summary>
  const  string UnifiedPayUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder";

    /// <summary>
    /// 网页授权接口
    /// </summary>
  const string access_tokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token";

    /// <summary>
    /// 微信订单查询接口
    /// </summary>
  const string OrderQueryUrl = "https://api.mch.weixin.qq.com/pay/orderquery";

        /// <summary>
        /// 随机串
        /// </summary>
        public static string getNoncestr()
        {
            Random random = new Random();
            return MD5Util.GetMD5(random.Next(1000).ToString(), "GBK").ToLower().Replace("s", "S");
        }

        /// <summary>
        /// 时间截,自1970年以来的秒数
        /// </summary>
        public static string getTimestamp()
        {
            TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
            return Convert.ToInt64(ts.TotalSeconds).ToString();
        }

        /// <summary>
        /// 网页授权接口
        /// </summary>
        public static string getAccess_tokenUrl()
        {
            return access_tokenUrl;
        }

        /// <summary>
        /// 获取微信签名
        /// </summary>
        /// <param name="sParams"></param>
        /// <returns></returns>
        public string getsign(SortedDictionary<string, string> sParams, string key)
        {
            int i = 0;
            string sign = string.Empty;
            StringBuilder sb = new StringBuilder();
            foreach (KeyValuePair<string, string> temp in sParams)
            {
                if (temp.Value == "" || temp.Value == null || temp.Key.ToLower() == "sign" )
                {
                    continue;
                }
                i++;
                sb.Append(temp.Key.Trim() + "=" + temp.Value.Trim() + "&");
            }
            sb.Append("key=" + key.Trim() + "");
            string signkey = sb.ToString();
            sign = MD5Util.GetMD5(signkey, "utf-8");


            return sign;
        }

        /// <summary>
        /// post数据到指定接口并返回数据
        /// </summary>
        public string PostXmlToUrl(string url, string postData)
        {
            //string returnmsg = "";
            //using (System.Net.WebClient wc = new System.Net.WebClient())
            //{
            //    returnmsg = wc.UploadString(url, "POST", postData);
            //}
            //return returnmsg;


            HttpWebRequest hwr = (HttpWebRequest)HttpWebRequest.Create(url);
            hwr.Method = "POST";

            Stream stream = hwr.GetRequestStream();

            StreamWriter sw = new StreamWriter(stream, System.Text.Encoding.UTF8);
            sw.Write(postData);
            sw.Close();

            stream = hwr.GetResponse().GetResponseStream();

            StreamReader sr = new StreamReader(stream, System.Text.Encoding.UTF8);
            string ret = sr.ReadToEnd();
            sr.Close();

            return ret;   
        }

        /// <summary>
        /// 获取prepay_id
        /// </summary>
        public string getPrepay_id(UnifiedOrder order, string key)
        {
            string prepay_id = "";
            string post_data = getUnifiedOrderXml(order, key);
            string request_data = PostXmlToUrl(UnifiedPayUrl, post_data);
            SortedDictionary<string, string> requestXML = GetInfoFromXml(request_data);
            foreach (KeyValuePair<string, string> k in requestXML)
            {
                if (k.Key == "prepay_id")
                {
                    prepay_id = k.Value;
                    break;
                }
            }
            return prepay_id;
        }

        /// <summary>
        /// 获取微信订单明细
        /// </summary>
        public OrderDetail getOrderDetail(QueryOrder queryorder, string key)
        {
            string post_data = getQueryOrderXml(queryorder, key);
            string request_data = PostXmlToUrl(OrderQueryUrl, post_data);
            OrderDetail orderdetail = new OrderDetail();
            SortedDictionary<string, string> requestXML = GetInfoFromXml(request_data);
            foreach (KeyValuePair<string, string> k in requestXML)
            {
                switch (k.Key)
                {
                    case "retuen_code":
                        orderdetail.result_code = k.Value;
                        break;
                    case "return_msg":
                        orderdetail.return_msg = k.Value;
                        break;
                    case "appid":
                        orderdetail.appid = k.Value;
                        break;
                    case "mch_id":
                        orderdetail.mch_id = k.Value;
                        break;
                    case "nonce_str":
                        orderdetail.nonce_str = k.Value;
                        break;
                    case "sign":
                        orderdetail.sign = k.Value;
                        break;
                    case "result_code":
                        orderdetail.result_code = k.Value;
                        break;
                    case "err_code":
                        orderdetail.err_code = k.Value;
                        break;
                    case "err_code_des":
                        orderdetail.err_code_des = k.Value;
                        break;
                    case "trade_state":
                        orderdetail.trade_state = k.Value;
                        break;
                    case "device_info":
                        orderdetail.device_info = k.Value;
                        break;
                    case "openid":
                        orderdetail.openid = k.Value;
                        break;
                    case "is_subscribe":
                        orderdetail.is_subscribe = k.Value;
                        break;
                    case "trade_type":
                        orderdetail.trade_type = k.Value;
                        break;
                    case "bank_type":
                        orderdetail.bank_type = k.Value;
                        break;
                    case "total_fee":
                        orderdetail.total_fee = k.Value;
                        break;
                    case "coupon_fee":
                        orderdetail.coupon_fee = k.Value;
                        break;
                    case "fee_type":
                        orderdetail.fee_type = k.Value;
                        break;
                    case "transaction_id":
                        orderdetail.transaction_id = k.Value;
                        break;
                    case "out_trade_no":
                        orderdetail.out_trade_no = k.Value;
                        break;
                    case "attach":
                        orderdetail.attach = k.Value;
                        break;
                    case "time_end":
                        orderdetail.time_end = k.Value;
                        break;
                    default:
                        break;
                }
            }
            return orderdetail;
        }

        /// <summary>
        /// 把XML数据转换为SortedDictionary<string, string>集合
        /// </summary>
        /// <param name="strxml"></param>
        /// <returns></returns>
        protected SortedDictionary<string, string> GetInfoFromXml(string xmlstring)
        {
            SortedDictionary<string, string> sParams = new SortedDictionary<string, string>();
            try
            {
                XmlDocument doc = new XmlDocument();
                doc.LoadXml(xmlstring);
                XmlElement root = doc.DocumentElement;
                int len = root.ChildNodes.Count;
                for (int i = 0; i < len; i++)
                {
                    string name = root.ChildNodes[i].Name;
                    if (!sParams.ContainsKey(name))
                    {
                        sParams.Add(name.Trim(), root.ChildNodes[i].InnerText.Trim());
                    }
                }
            }
            catch { }
            return sParams;
        }

        /// <summary>
        /// 微信统一下单接口xml参数整理
        /// </summary>
        /// <param name="order">微信支付参数实例</param>
        /// <param name="key">密钥</param>
        /// <returns></returns>
        protected string getUnifiedOrderXml(UnifiedOrder order, string key)
        {
            string return_string = string.Empty;
            SortedDictionary<string, string> sParams = new SortedDictionary<string, string>();
            sParams.Add("appid", order.appid);
            sParams.Add("attach", order.attach);
            sParams.Add("body", order.body);
            sParams.Add("device_info", order.device_info);
            sParams.Add("mch_id", order.mch_id);
            sParams.Add("nonce_str", order.nonce_str);
            sParams.Add("notify_url", order.notify_url);
            sParams.Add("openid", order.openid);
            sParams.Add("out_trade_no", order.out_trade_no);
            sParams.Add("spbill_create_ip", order.spbill_create_ip);
            sParams.Add("total_fee", order.total_fee.ToString());
            sParams.Add("trade_type", order.trade_type);
            order.sign = getsign(sParams, key);
            sParams.Add("sign", order.sign);

            //拼接成XML请求数据
            StringBuilder sbPay = new StringBuilder();
            foreach (KeyValuePair<string, string> k in sParams)
            {
                //if (k.Key == "attach" || k.Key == "body" || k.Key == "sign")
                //{
                //    sbPay.Append("<" + k.Key + "><![CDATA[" + k.Value + "]]></" + k.Key + ">");
                //}
                //else
                //{
                    sbPay.Append("<" + k.Key + ">" + k.Value + "</" + k.Key + ">");
               // }
            }
            return_string = string.Format("<xml>{0}</xml>", sbPay.ToString());
            byte[] byteArray = Encoding.UTF8.GetBytes(return_string);
            return_string = Encoding.GetEncoding("UTF-8").GetString(byteArray);
            return return_string;
            
        }

        /// <summary>
        /// 微信订单查询接口XML参数整理
        /// </summary>
        /// <param name="queryorder">微信订单查询参数实例</param>
        /// <param name="key">密钥</param>
        /// <returns></returns>
        protected string getQueryOrderXml(QueryOrder queryorder, string key)
        {
            string return_string = string.Empty;
            SortedDictionary<string, string> sParams = new SortedDictionary<string, string>();
            sParams.Add("appid", queryorder.appid);
            sParams.Add("mch_id", queryorder.mch_id);
            sParams.Add("transaction_id", queryorder.transaction_id);
            sParams.Add("out_trade_no", queryorder.out_trade_no);
            sParams.Add("nonce_str", queryorder.nonce_str);
            queryorder.sign = getsign(sParams, key);
            sParams.Add("sign", queryorder.sign);

            //拼接成XML请求数据
            StringBuilder sbPay = new StringBuilder();
            foreach (KeyValuePair<string, string> k in sParams)
            {
                if (k.Key == "attach" || k.Key == "body" || k.Key == "sign")
                {
                    sbPay.Append("<" + k.Key + "><![CDATA[" + k.Value + "]]></" + k.Key + ">");
                }
                else
                {
                    sbPay.Append("<" + k.Key + ">" + k.Value + "</" + k.Key + ">");
                }
            }
            return_string = string.Format("<xml>{0}</xml>", sbPay.ToString().TrimEnd(','));
            return return_string;
        }
    
	}


MD5加密:

 public class MD5Util
    {
        public MD5Util()
        {
            //
            // TODO: 在此处添加构造函数逻辑
            //
        }

        /** 获取大写的MD5签名结果 */
        public static string GetMD5(string encypStr, string charset)
        {
            string retStr;
            MD5CryptoServiceProvider m5 = new MD5CryptoServiceProvider();

            //创建md5对象
            byte[] inputBye;
            byte[] outputBye;

            //使用GB2312编码方式把字符串转化为字节数组.
            try
            {
                inputBye = Encoding.GetEncoding(charset).GetBytes(encypStr);
            }
            catch (Exception ex)
            {
                inputBye = Encoding.GetEncoding("GB2312").GetBytes(encypStr);
            }
            outputBye = m5.ComputeHash(inputBye);

            retStr = System.BitConverter.ToString(outputBye);
            retStr = retStr.Replace("-", "").ToUpper();
            return retStr;
        }
    }

Pay.aspx主要内容
   //支付信息
        function Pay() {
            var appId = "<%=appId %>";
            var timeStamp = "<%=timeStamp %>";
            var nonceStr = "<%=nonceStr %>";
            var prepay_id = "<%=prepay_id %>";
            var paySign = "<%=paySign %>";
            var OrderID = "<%=OrderID %>";
            //alert("appId:" + appId + ",timeStamp:" + timeStamp + ",nonceStr:" + nonceStr + ",prepay_id:" + prepay_id + ",paySign:" + paySign);
            //return;
            function onBridgeReady() {
                WeixinJSBridge.invoke(
                'getBrandWCPayRequest', {
               "appId": appId,     //公众号名称,由商户传入     
               "timeStamp": timeStamp,         //时间戳,自1970年以来的秒数     
               "nonceStr": nonceStr, //随机串     
               "package": "prepay_id=" + prepay_id,
               "signType": "MD5",         //微信签名方式:     
               "paySign": paySign //微信签名 
       },
       function (res) {
           if (res.err_msg == "get_brand_wcpay_request:ok") {

               $.showLoading("正在校验支付");
               //检查是否支付成功
               $.get("Tools/CheckPay.aspx?OrderId=" + OrderID, function (data) {

                   $.hideLoading();
                   if (data == "success") {
                       alert("支付成功");
                       window.location.href = "Order.aspx?OrderID=" + OrderID + "&OpenId=" + '<%=OpenID %>' + "&M=" + Math.random();
                   }
                   else {
                       alert("支付待验证,返回结果:" + data);
                       window.location.href = "Order.aspx?OrderID=" + OrderID + "&OpenId=" + '<%=OpenID %>' + "&M=" + Math.random();
                   }
               }); //get结束
           }     // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回    ok,但并不保证它绝对可靠。 
           else {
               alert("交易取消");
               window.location.href = "Order.aspx?OrderID=" + OrderID + "&OpenId=" + '<%=OpenID %>' + "&M=" + Math.random();
           }


       }
   );
            }
            if (typeof WeixinJSBridge == "undefined") {
                if (document.addEventListener) {
                    document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
                } else if (document.attachEvent) {
                    document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
                    document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
                }
            } else {
                onBridgeReady();
            }
        }



Pay.aspx.cs 主要内容


  private void PayInfo(string OpenId, string OrderId, string OrderAmount, string paySignKey)
    {
        try
        {
            TenpayUtil tenpay = new TenpayUtil();
            UnifiedOrder order = new UnifiedOrder();
            order.appid = "这里是APPID";
            order.attach = "随便写";
            order.body = "这里是订单内容";
            order.device_info = "";
            order.mch_id = "这里是微信支付的商户号";//商户号
            order.nonce_str = TenpayUtil.getNoncestr();
            order.notify_url = "回调通知地址";
            order.openid = OpenId;
            order.out_trade_no = OrderId;
            order.trade_type = "JSAPI";
            order.spbill_create_ip = Page.Request.UserHostAddress;
            order.total_fee = int.Parse(OrderAmount);
            //order.total_fee = int.Parse("12") * 100;

            prepay_id = tenpay.getPrepay_id(order, paySignKey);

            timeStamp = TenpayUtil.getTimestamp();
            nonceStr = TenpayUtil.getNoncestr();

            SortedDictionary<string, string> sParams = new SortedDictionary<string, string>();
            sParams.Add("appId", appId);
            sParams.Add("timeStamp", timeStamp);
            sParams.Add("nonceStr", nonceStr);
            sParams.Add("package", "prepay_id=" + prepay_id);
            sParams.Add("signType", "MD5");
            paySign = tenpay.getsign(sParams, paySignKey);


          

        }
        catch (Exception ex)
        {
            Response.Write(ex.Message);
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值