Asp.net 微信H5唤起支付和支付回调


做任何商城类的项目都离不开支付这一环节,今天就记录一下在开发微信H5支付时的开发过程

在开发到订单这部分模块的时候终于遇到了微信开发第二个难题,微信支付!

首先请阅读 微信JSAPI支付文档  和 微信统一下单API 了解场景和参数

微信支付需要有 微信公众平台 和 微信商户平台 账号

 

在微信商户平台配置 API秘钥

 

配置 JSAPI域名

 

配置完这些之后 开始写 WechatHelper 所用到的类

 

目录

 

Data 用来存放需要用到的参数

 public class WxPayData
    {
        public WxPayData()
        {

        }

        //采用排序的Dictionary的好处是方便对数据包进行签名,不用再签名之前再做一次排序
        private SortedDictionary<string, object> m_values = new SortedDictionary<string, object>();

        /**
        * 设置某个字段的值
        * @param key 字段名
         * @param value 字段值
        */
        public void SetValue(string key, object value)
        {
            m_values[key] = value;
        }

        /**
        * 根据字段名获取某个字段的值
        * @param key 字段名
         * @return key对应的字段值
        */
        public object GetValue(string key)
        {
            object o = null;
            m_values.TryGetValue(key, out o);
            return o;
        }

        /**
         * 判断某个字段是否已设置
         * @param key 字段名
         * @return 若字段key已被设置,则返回true,否则返回false
         */
        public bool IsSet(string key)
        {
            object o = null;
            m_values.TryGetValue(key, out o);
            if (null != o)
                return true;
            else
                return false;
        }

        /**
        * @将Dictionary转成xml
        * @return 经转换得到的xml串
        * @throws WxPayException
        **/
        public string ToXml()
        {
            //数据为空时不能转化为xml格式
            if (0 == m_values.Count)
            {
                throw new WxPayException("WxPayData数据为空!");
            }

            string xml = "<xml>";
            foreach (KeyValuePair<string, object> pair in m_values)
            {
                //字段值不能为null,会影响后续流程
                if (pair.Value == null)
                {
                    throw new WxPayException("WxPayData内部含有值为null的字段!");
                }

                if (pair.Value.GetType() == typeof(int))
                {
                    xml += "<" + pair.Key + ">" + pair.Value + "</" + pair.Key + ">";
                }
                else if (pair.Value.GetType() == typeof(string))
                {
                    xml += "<" + pair.Key + ">" + "<![CDATA[" + pair.Value + "]]></" + pair.Key + ">";
                }
                else//除了string和int类型不能含有其他数据类型
                {
                    throw new WxPayException("WxPayData字段数据类型错误!");
                }
            }
            xml += "</xml>";
            return xml;
        }

        /**
        * @将xml转为WxPayData对象并返回对象内部的数据
        * @param string 待转换的xml串
        * @return 经转换得到的Dictionary
        * @throws WxPayException
        */
        public SortedDictionary<string, object> FromXml(string xml)
        {
            if (string.IsNullOrEmpty(xml))
            {
                throw new WxPayException("将空的xml串转换为WxPayData不合法!");
            }

            XmlDocument xmlDoc = new Xml.XmlDocument_XxeFixed();
            xmlDoc.LoadXml(xml);
            XmlNode xmlNode = xmlDoc.FirstChild;//获取到根节点<xml>
            XmlNodeList nodes = xmlNode.ChildNodes;
            foreach (XmlNode xn in nodes)
            {
                XmlElement xe = (XmlElement)xn;
                m_values[xe.Name] = xe.InnerText;//获取xml的键值对到WxPayData内部的数据中
            }

            try
            {
                //2015-06-29 错误是没有签名
                if (m_values["return_code"].ToString() != "SUCCESS")
                {
                    return m_values;
                }
                CheckSign();//验证签名,不通过会抛异常
            }
            catch (WxPayException ex)
            {
                throw new WxPayException(ex.Message);
            }

            return m_values;
        }

        /**
        * @Dictionary格式转化成url参数格式
        * @ return url格式串, 该串不包含sign字段值
        */
        public string ToUrl()
        {
            string buff = "";
            foreach (KeyValuePair<string, object> pair in m_values)
            {
                if (pair.Value == null)
                {
                    throw new WxPayException("WxPayData内部含有值为null的字段!");
                }

                if (pair.Key != "sign" && pair.Value.ToString() != "")
                {
                    buff += pair.Key + "=" + pair.Value + "&";
                }
            }
            buff = buff.Trim('&');
            return buff;
        }


        /**
        * @Dictionary格式化成Json
         * @return json串数据
        */
        public string ToJson()
        {
          //  string jsonStr = JsonMapper.ToJson(m_values);
            return "";
        }

        /**
        * @values格式化成能在Web页面上显示的结果(因为web页面上不能直接输出xml格式的字符串)
        */
        public string ToPrintStr()
        {
            string str = "";
            foreach (KeyValuePair<string, object> pair in m_values)
            {
                if (pair.Value == null)
                {
                    throw new WxPayException("WxPayData内部含有值为null的字段!");
                }

                str += string.Format("{0}={1}<br>", pair.Key, pair.Value.ToString());
            }
            return str;
        }

        /**
        * @生成签名,详见签名生成算法
        * @return 签名, sign字段不参加签名
        */
        public string MakeSign()
        {
            //转url格式
            string str = ToUrl();
            //在string后加入API KEY
            str += "&key=" + WechatConfig.Key;
            //MD5加密
            var md5 = MD5.Create();
            var bs = md5.ComputeHash(Encoding.UTF8.GetBytes(str));
            var sb = new StringBuilder();
            foreach (byte b in bs)
            {
                sb.Append(b.ToString("x2"));
            }
            //所有字符转为大写
            return sb.ToString().ToUpper();
        }

        /**
        * 
        * 检测签名是否正确
        * 正确返回true,错误抛异常
        */
        public bool CheckSign()
        {
            //如果没有设置签名,则跳过检测
            if (!IsSet("sign"))
            {
                throw new WxPayException("WxPayData签名存在但不合法!");
            }
            //如果设置了签名但是签名为空,则抛异常
            else if (GetValue("sign") == null || GetValue("sign").ToString() == "")
            {
                throw new WxPayException("WxPayData签名存在但不合法!");
            }

            //获取接收到的签名
            string return_sign = GetValue("sign").ToString();

            //在本地计算新的签名
            string cal_sign = MakeSign();

            if (cal_sign == return_sign)
            {
                return true;
            }

            throw new WxPayException("WxPayData签名验证错误!");
        }

        /**
        * @获取Dictionary
        */
        public SortedDictionary<string, object> GetValues()
        {
            return m_values;
        }
    }

 

 Exception

 public class WxPayException : Exception
    {
        public WxPayException(string msg) : base(msg)
        {
        }
    }

 

HttpService

用于发送请求,访问微信统一下单API 和 查询订单接口

public class HttpService
    {

        public static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            return true;
        }

        public static string Post(string xml, string url, bool isUseCert, int timeout)
        {
            GC.Collect();//垃圾回收,回收没有正常关闭的http连接

            string result = "";//返回结果

            HttpWebRequest request = null;
            HttpWebResponse response = null;
            Stream reqStream = null;

            try
            {
                //设置最大连接数
                ServicePointManager.DefaultConnectionLimit = 200;
                //设置https验证方式
                if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
                {
                    ServicePointManager.ServerCertificateValidationCallback =
                            new RemoteCertificateValidationCallback(CheckValidationResult);
                }

                /***************************************************************
                * 下面设置HttpWebRequest的相关属性
                * ************************************************************/
                request = (HttpWebRequest)WebRequest.Create(url);

                request.Method = "POST";
                request.Timeout = timeout * 1000;

                //设置代理服务器
                //WebProxy proxy = new WebProxy();                          //定义一个网关对象
                //proxy.Address = new Uri(WxPayConfig.PROXY_URL);              //网关服务器端口:端口
                //request.Proxy = proxy;

                //设置POST的数据类型和长度
                request.ContentType = "text/xml";
                byte[] data = Encoding.UTF8.GetBytes(xml);
                request.ContentLength = data.Length;

                ////是否使用证书
                //if (isUseCert)
                //{
                //    string path = HttpContext.Current.Request.PhysicalApplicationPath;
                //    X509Certificate2 cert = new X509Certificate2(path + WxPayConfig.SSLCERT_PATH, WxPayConfig.SSLCERT_PASSWORD);
                //    request.ClientCertificates.Add(cert);
                //}

                //往服务器写入数据
                reqStream = request.GetRequestStream();
                reqStream.Write(data, 0, data.Length);
                reqStream.Close();

                //获取服务端返回
                response = (HttpWebResponse)request.GetResponse();

                //获取服务端返回数据
                StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
                result = sr.ReadToEnd().Trim();
                sr.Close();
            }
            catch (System.Threading.ThreadAbortException e)
            {
                System.Threading.Thread.ResetAbort();
            }
            catch (WebException e)
            {
                throw new WxPayException(e.ToString());
            }
            catch (Exception e)
            {
                throw new WxPayException(e.ToString());
            }
            finally
            {
                //关闭连接和流
                if (response != null)
                {
                    response.Close();
                }
                if (request != null)
                {
                    request.Abort();
                }
            }
            return result;
        }
    }

 

WechatConfig 微信支付统一下单所用到的参数 会读取 /App_Data/xml/payment.xml 文件里面的内容

appid:微信公众平台的开发者ID(AppID)

mchid:微信商户平台账号

key:在微信商户平台设置的API密钥

appsecret:在微信公众平台中设置的开发者密码(AppSecret)

ip:终端IP

notify_url:微信支付异步回调地址,在微信支付成功时会异步调用你的接口

gateway:微信支付统一下单API接口

queryorder:微信支付查询订单接口

sealed class WechatConfig
    {
        #region 字段
        static string appid = string.Empty;
        static string mchid = string.Empty;
        static string key = string.Empty;
        static string appsecret = string.Empty;
        static string notify_url = string.Empty;
        static string gateway = string.Empty;
        static string queryorder = string.Empty;
        #endregion

        static WechatConfig()
        {
            XmlDocument xml = new Xml.XmlDocument_XxeFixed();
            xml.XmlResolver = null;
            xml.Load(HttpContext.Current.Server.MapPath("/App_Data/xml/payment.xml"));
            var root = xml.SelectSingleNode("paymentMethod").ChildNodes;
            foreach (XmlNode xn in root)
            {
                XmlElement xe = (XmlElement)xn;
                if (xe.GetAttribute("id") == "wechatpay")
                {
                    appid = xe.GetAttribute("appid");
                    mchid = xe.GetAttribute("mchid");
                    key = xe.GetAttribute("key");
                    appsecret = xe.GetAttribute("appsecret");
                    notify_url = xe.GetAttribute("notify_url");
                    gateway = xe.GetAttribute("gateway");
                    queryorder = xe.GetAttribute("queryorder");
                    break;
                }
            }
        }

        internal static string Gateway
        {
            get
            {
                return gateway;
            }
        }
        internal static string Appid
        {
            get
            {
                return appid;
            }
        }
        internal static string Mchid
        {
            get
            {
                return mchid;
            }
        }
        internal static string Appsecret
        {
            get
            {
                return appsecret;
            }
        }
        internal static string Key
        {
            get
            {
                return key;
            }
        }
        internal static string Queryorder
        {
            get
            {
                return queryorder;
            }
        }
        internal static string Notify_url
        {
            get
            {
                return notify_url;
            }
        }
    }

 

WechatHelper  

在业务处理层调用 根据不同场景传入不同的参数,可用于一个项目多个支付场景

out_trade_no :商户支付的订单号由商户自定义生成,仅支持使用字母、数字、中划线-、下划线_、竖线|、星号*这些英文半角字符的组合,请勿使用汉字或全角等特殊字符。微信支付要求商户订单号保持唯一性(建议根据当前系统时间加随机序列来生成订单号)。重新发起一笔支付要使用原订单号,避免重复支付;已支付过或已调用关单、撤销的订单号不能重新发起支付。

total_fee:订单总金额,单位为分 这里在方法里对金额进行了处理 可直接传实际金额

attach:附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用。用于区分不同的支付场景,在回调中可以根据此来调用不同的方法

body:商品简单描述

ip:终端ip

trade_type:交易类型 JSAPI -JSAPI支付  NATIVE -Native支付  APP -APP支付

openId:此参数为微信用户在商户对应appid下的唯一标识

 public sealed class WechatHelper
    {
        #region JSAPI Pay

        /// <summary>
        /// JSAPI Pay
        /// </summary>
        /// <param name="out_trade_no">订单编号</param>
        /// <param name="total_fee">价格</param>
        /// <param name="attach">自定义参数,回调回传</param>
        /// <returns></returns>
        public static ResultModel JSApiPay(string out_trade_no, decimal total_fee, string openid, string ip, string attach = "", string body = "购买商品")
        {
            WxPayData result = Pay(out_trade_no, total_fee, attach, body, ip, "JSAPI", openid);
            string return_code = result.GetValue("return_code").ToString();//返回状态码  SUCCESS/FAIL 
            string result_code = result.GetValue("result_code").ToString();//返回状态码  SUCCESS/FAIL 
            if (return_code == "SUCCESS" && result_code == "SUCCESS")
            {
              //  string url = result.GetValue("prepay_id").ToString();//预付款订单prepay_id
                ResultModel rm = new ResultModel();
                rm.appId = WechatConfig.Appid;
                rm.timeStamp = WxPayApi.GenerateTimeStamp();
                rm.nonceStr = result.GetValue("nonce_str").ToString();
                rm.package = "prepay_id=" + result.GetValue("prepay_id").ToString();
                //设置支付参数
                var paySignReqHandler = new RequestHandler(null);
                paySignReqHandler.SetParameter("appId", rm.appId);
                paySignReqHandler.SetParameter("timeStamp", rm.timeStamp);
                paySignReqHandler.SetParameter("nonceStr", rm.nonceStr);
                paySignReqHandler.SetParameter("package", rm.package);
                paySignReqHandler.SetParameter("signType", "MD5");
                var paySign = paySignReqHandler.CreateMd5Sign("key", WechatConfig.Key);
                rm.paySign = paySign;
                return rm;
            }
            return null;
        }

        #endregion

        public static WxPayData Pay(string out_trade_no, decimal total_fee, string attach, string body, string ip, string trade_type, string openId = "")
        {
            var paymoney = Convert.ToInt32(total_fee * 100);
            WxPayData data = new WxPayData();
            data.SetValue("body", body);//商品描述
            data.SetValue("attach", attach);//附加数据,回调返回
            data.SetValue("out_trade_no", out_trade_no);//订单编号
            data.SetValue("total_fee", paymoney.ToString());//总金额
            data.SetValue("time_start", DateTime.Now.ToString("yyyyMMddHHmmss"));//交易起始时间
            data.SetValue("time_expire", DateTime.Now.AddMinutes(10).ToString("yyyyMMddHHmmss"));//交易结束时间
            data.SetValue("goods_tag", "");//商品标记,订单优惠标记,使用代金券或立减优惠功能时需要的参数
            data.SetValue("trade_type", trade_type);//交易类型
            if (trade_type == "JSAPI")
            {
                data.SetValue("openid", openId);//openId
            }
            data.SetValue("product_id", out_trade_no);//商品ID
            return WxPayApi.UnifiedOrder(data, ip);//调用统一下单接口
        }
        public static WxPayData GetNotifyData(Stream InputStream)
        {
            //接收从微信后台POST过来的数据
            Stream s = InputStream;
            int count = 0;
            byte[] buffer = new byte[1024];
            StringBuilder builder = new StringBuilder();
            while ((count = s.Read(buffer, 0, 1024)) > 0)
            {
                builder.Append(Encoding.UTF8.GetString(buffer, 0, count));
            }
            s.Flush();
            s.Close();
            s.Dispose();
            //转换数据格式并验证签名
            WxPayData data = new WxPayData();
            try
            {
                data.FromXml(builder.ToString());
            }
            catch (WxPayException ex)
            {
                //若签名错误,则立即返回结果给微信支付后台
                WxPayData res = new WxPayData();
                res.SetValue("return_code", "FAIL");
                res.SetValue("return_msg", ex.Message);
            }
            return data;
        }

        //查询订单
        public static bool QueryOrder(string transaction_id)
        {
            WxPayData req = new WxPayData();
            req.SetValue("transaction_id", transaction_id);
            WxPayData res = WxPayApi.OrderQuery(req);
            if (res.GetValue("return_code").ToString() == "SUCCESS" &&
                res.GetValue("result_code").ToString() == "SUCCESS")
            {
                return true;
            }
            else
            {
                return false;
            }
        }

    }
    public class ResultModel
    {
        public string appId { get; set; }
        public string timeStamp { get; set; }
        public string nonceStr { get; set; }
        public string package { get; set; }
        public string paySign { get; set; }
    }

 

 

WxPayApi

在wechathelper中拿到业务参数之后到wxpayapi中加入固定参数

public class WxPayApi
    {

        /**
        * 
        * 统一下单
        * @param WxPaydata inputObj 提交给统一下单API的参数
        * @param int timeOut 超时时间
        * @throws WxPayException
        * @return 成功时返回,其他抛异常
        */
        public static WxPayData UnifiedOrder(WxPayData inputObj,string ip, int timeOut = 6)
        {
            //检测必填参数
            if (!inputObj.IsSet("out_trade_no"))
            {
                throw new WxPayException("缺少统一支付接口必填参数out_trade_no!");
            }
            else if (!inputObj.IsSet("body"))
            {
                throw new WxPayException("缺少统一支付接口必填参数body!");
            }
            else if (!inputObj.IsSet("total_fee"))
            {
                throw new WxPayException("缺少统一支付接口必填参数total_fee!");
            }
            else if (!inputObj.IsSet("trade_type"))
            {
                throw new WxPayException("缺少统一支付接口必填参数trade_type!");
            }
            //关联参数
            if (inputObj.GetValue("trade_type").ToString() == "JSAPI" && !inputObj.IsSet("openid"))
            {
                throw new WxPayException("统一支付接口中,缺少必填参数openid!trade_type为JSAPI时,openid为必填参数!");
            }
            if (inputObj.GetValue("trade_type").ToString() == "NATIVE" && !inputObj.IsSet("product_id"))
            {
                throw new WxPayException("统一支付接口中,缺少必填参数product_id!trade_type为JSAPI时,product_id为必填参数!");
            }
            inputObj.SetValue("notify_url", WechatConfig.Notify_url);//异步通知url
            inputObj.SetValue("appid", WechatConfig.Appid);//公众账号ID
            inputObj.SetValue("mch_id", WechatConfig.Mchid);//商户号
            inputObj.SetValue("spbill_create_ip", ip);//终端ip              
            inputObj.SetValue("nonce_str", GenerateNonceStr());//随机字符串
            //签名
            inputObj.SetValue("sign", inputObj.MakeSign());
            string xml = inputObj.ToXml();
            string response = HttpService.Post(xml, WechatConfig.Gateway, false, timeOut);
            WxPayData result = new WxPayData();
            result.FromXml(response);

            //ReportCostTime(url, timeCost, result);//测速上报

            return result;
        }

        /**
        * 生成时间戳,标准北京时间,时区为东八区,自1970年1月1日 0点0分0秒以来的秒数
         * @return 时间戳
        */
        public static string GenerateTimeStamp()
        {
            TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
            return Convert.ToInt64(ts.TotalSeconds).ToString();
        }

        /**
        * 生成随机串,随机串包含字母或数字
        * @return 随机串
        */
        public static string GenerateNonceStr()
        {
            return Guid.NewGuid().ToString().Replace("-", "");
        }

        /**
        *    
        * 查询订单
        * @param WxPayData inputObj 提交给查询订单API的参数
        * @param int timeOut 超时时间
        * @throws WxPayException
        * @return 成功时返回订单查询结果,其他抛异常
        */
        public static WxPayData OrderQuery(WxPayData inputObj, int timeOut = 6)
        {
            string url = "https://api.mch.weixin.qq.com/pay/orderquery";
            inputObj.SetValue("appid", WechatConfig.Appid);//公众账号ID
            inputObj.SetValue("mch_id", WechatConfig.Mchid);//商户号
            inputObj.SetValue("nonce_str",GenerateNonceStr());//随机字符串
            inputObj.SetValue("sign", inputObj.MakeSign());//签名

            string xml = inputObj.ToXml();

            var start = DateTime.Now;

            string response = HttpService.Post(xml, url, false, timeOut);//调用HTTP通信接口提交数据
            var end = DateTime.Now;
            int timeCost = (int)((end - start).TotalMilliseconds);//获得接口耗时

            //将xml格式的数据转化为对象以返回
            WxPayData result = new WxPayData();
            result.FromXml(response);

            // ReportCostTime(url, timeCost, result);//测速上报

            return result;
        }

        /***
    * 订单查询完整业务流程逻辑
    * @param transaction_id 微信订单号(优先使用)
    * @param out_trade_no 商户订单号
    * @return 订单查询结果(xml格式)
    */
        public static WxPayData Run(string transaction_id, string out_trade_no)
        {

            WxPayData data = new WxPayData();
            if (!string.IsNullOrEmpty(transaction_id))//如果微信订单号存在,则以微信订单号为准
            {
                data.SetValue("transaction_id", transaction_id);
            }
            else//微信订单号不存在,才根据商户订单号去查单
            {
                data.SetValue("out_trade_no", out_trade_no);
            }

            WxPayData result = OrderQuery(data);//提交订单查询请求给API,接收返回数据
            return result;
        }


    }

 

这样一个完整的wechathelper类就搭建完成了

 

创建xml配置文件 payment.xml

<?xml version="1.0" encoding="utf-8" ?>
<paymentMethod>
  <info
  id="wechatpay"
  appid=""
  mchid=""
  key=""
  appsecret=""
  ip=""
  notify_url="http://xxx/pay/WechatNotify"
  gateway="https://api.mch.weixin.qq.com/pay/unifiedorder"
  queryorder="https://api.mch.weixin.qq.com/pay/orderquery" />
</paymentMethod>

 

在控制器中创建 WechatHelper 调用JSApiPay方法

public ActionResult PayView(){
            WechatHelper wechatPay = new WechatHelper();
                    var pay = wechatPay.JSApiPay(OrderNum, Price, WxOpenId, "ip", "5");
                    var jssdkUiPackage = JSSDKHelper.GetJsSdkUiPackage(APPID, SECRET), Request.Url.AbsoluteUri);
                    ViewBag.JssdkUiPackage = jssdkUiPackage;
                    ViewBag.uid = user.Id;
                    ViewBag.orderNum = order.OrderNum;
                    JsSdkUiPackage jup = jssdkUiPackage as JsSdkUiPackage;
                    return View(pay);
}

 

 

创建支付页面

@{
    var jssdk = ViewBag.JssdkUiPackage as Senparc.Weixin.MP.Helpers.JsSdkUiPackage;
    var uid = ViewBag.uid;
    var ordernum = ViewBag.orderNum;
}

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>微信支付</title>
</head>
<body>
    <input type="hidden" id="appid" value="@Model.appId" />
    <input type="hidden" id="timestamp" value="@Model.timeStamp" />
    <input type="hidden" id="nonceStr" value="@Model.nonceStr" />
    <input type="hidden" id="signature" value="@Model.paySign" />
    <input type="hidden" id="wxpackage" value="@Model.package" />
    <input type="hidden" id="uid" value="@uid" />

    <input type="hidden" id="_timestamp" value="@jssdk.Timestamp" />
    <input type="hidden" id="_nonceStr" value="@jssdk.NonceStr" />
    <input type="hidden" id="_signature" value="@jssdk.Signature" />
    <input type="hidden" id="ordernum" value="@ordernum" />
    <input type="hidden" id="types" value="1" />

    <script src="~/scripts/plug/jquery-1.9.1.min.js"></script>
    <script src="~/scripts/plug/jweixin-1.2.0.js"></script>
    <script src="~/scripts/plug/wechatpay.js"></script>
</body>
</html>

 

wechatpay.js

var appid = $("#appid").val();
var timestamp = $("#timestamp").val();
var nonceStr = $("#nonceStr").val();
var signature = $("#signature").val();
var wxpackage = $("#wxpackage").val();
var uid = $("#uid").val();
var _timestamp = $("#_timestamp").val();
var _nonceStr = $("#_nonceStr").val();
var _signature = $("#_signature").val();

var types = $("#types").val();

wx.config({
    debug: false,
    appId: appid, // 公众号的唯一标识
    timestamp: _timestamp, //生成签名的时间戳
    nonceStr: _nonceStr, // 生成签名的随机串
    signature: _signature,// 签名
    jsApiList: ['chooseWXPay', 'translateVoice']
});

wx.ready(function () {
    wx.chooseWXPay({
        timestamp: timestamp,
        nonceStr: nonceStr,
        package: wxpackage,
        signType: 'MD5',
        paySign: signature,
        success: function (res) {
            if (res.errMsg == "chooseWXPay:ok") {
                window.location.href = "/pay/Pay_Success";
            } else {
                window.location.href = "/pay/Pay_Error";
            }
        },
        fail: function (res) {
            window.location.href = "/pay/Pay_Error";
        },
        cancel: function (res) {
            window.location.href = "/pay/Pay_Error";
        }
    });
});

 

微信支付异步回调

这里就是支付成功之后微信异步回调的接口方法

参数可以参考 微信API文档  支付结果通知 

 #region 微信支付异步回调

        [HttpPost]
        [Transaction]
        public ActionResult WechatNotify()
        {
            try
            {
                WechatHelper wechatPay = new WechatHelper();
                WxPayData notifyData = wechatPay.GetNotifyData(Request.InputStream);
                string attach = notifyData.GetValue("attach").ToString();string transaction_id = notifyData.GetValue("transaction_id").ToString();
                if (!notifyData.IsSet("transaction_id"))
                {
                    log("回调return_msg=支付结果中微信订单号不存在", "wechatpayer");
                }
                if (!wechatPay.QueryOrder(transaction_id))
                {
                    log("回调return_msg=订单查询失败", "wechatpayer");
                }
                else
                {
                    log("回调return_msg=OK", "wechatpayer");
                }
                var payxml = XDocument.Parse(notifyData.ToXml());
                if (payxml.Element("xml").Element("return_code").Value == "SUCCESS")
                {
                    if (payxml.Element("xml").Element("result_code").Value == "SUCCESS")
                    {
                        string out_trade_no = payxml.Element("xml").Element("out_trade_no").Value;
                    }
                    return Content("<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[交易失败]]></return_msg></xml>");
                }
                return Content("<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[交易失败]]></return_msg></xml>");
            }
            catch (Exception ex)
            {
                log(ex.ToString(), "wechatpayer");
                return Content("<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[交易失败]]></return_msg></xml>");
            }
        }


        #endregion

 

这样就完成了在微信H5中唤起微信支付 并且通过异步回调 完成一些业务

边记录边学习 欢迎各位一起探讨

 

文章来源:https://www.cnblogs.com/kangsir7/p/15762942.html

版权声明:本文为YES开发框架网发布内容,转载请附上原文出处连接
管理员
上一篇:.NET Core定时任务(控制台程序)
下一篇:手把手教你学Dapr - 7. Actors
评论列表

发表评论

评论内容
昵称:
验证码:
验证码
关联文章

Asp.net H5唤起支付支付
支付支付成功没有通知Notify_URL
支付: API V3支付签名验证
ASP.Net H5 OAuth2 认证 (前后端不分离)
支付:签名计算.net4.5
支付:JSAPI支付 开发手册
支付宝:H5 JSAPI支付开发手册
支付,当面付,开发手册
支付宝:当面付支付完成异步
【已解决】.NET 支付API V3中JSAPI支付发起wx.chooseWXPay时,提示 支付验证签名失败
支付: API V3支付签名验证
支付官方相关工具下载
支付:C#计算签名
支付:API v3 Postman脚本使用指南
/支付宝 在线支付测试工具
支付:Http头缺少Accept或User-Agent
支付提示 No_Auth 受理关系不存在
支付接口签名校验工具
.net 简单实现在H5中将word、jpg、png转成PDF给PDF添加水印并且控制样式可视化编辑
支付参数登记

热门标签
.NET Core .NET Reactor ag-grid AI发布 api安全 ASP.NET Core C#DLL加密 C#播放声音 C#代码混淆 C#代码加密 ChromeDriver Codex DateTime DBeaver devexpress devTool DLL混淆 edge.js EF EFCore Electron element-ui el-form el-table excel FastReport FileStream FolderBrowerDialog FolderSelectDialog form提交 git gridcontrol gridview input javascript json字符串 JS转换对象JSON jwt JWT授权 linq log Math MCP mitmproxy MVC MySQL Navicat netstat nginx node_modules NSwag Nuget Nuget镜像 number PowerShell pyinstaller python pythoncom python爬虫 python抓包 pywin32 redis Requests-html RestSharp Selenium sql SQL Server Swagger to-cms Visual Studio VSCode vue VueRouter vue路由 VUE页面通讯 Webpack Windows Windows服务 winform wmi xlrd yaml YESCMS YESWEB开发框架 白象 表单提交 播放声音 打开URL 代码混淆 弹窗提醒 端口占用 对象转换 分布式 公共字典 机器码 进程排查 静态资源 开发指南 路由参数 密钥 配置教程 配置文件 权限 人工智能 任务 任务调度 日期间隔 日志 日志记录 省市区 授权验证 数据库 四舍五入 文案 文件读取 文件夹选择 文件目录选择 问题排查 行政区域数据 页面通讯 中间件 CSharp 事务锁 工单系统 并发控制 重复提交 CMS Markdig Markdown markdown-it marked 技术选型 VS Code 开发工具 源代码管理 版本控制 Docker PostgreSQL 时区 部署排查 CMS架构 EF Core 主题系统 二次开发 插件系统 容器 运维命令 镜像清理 Linux NAS 远程挂载 飞牛 fnOS S/4HANA SAP GUI SAP HANA SAP R/3 SAP入门 SAP版本 ERP SAP SAP MM 库存管理 物料管理 采购管理 入门教程 SAP S/4HANA SPRO 企业结构 采购组织 MM01 物料主数据 物料类型 BP分组 业务伙伴 供应商主数据 ME41 RFQ 库存物料 采购流程 ME51 消耗性物料 科目分配 采购申请 AC03 ML81N 外部服务 服务主数据 Business Partner SAP培训 ME51N MM模块 Lean Services MM-SRV 外部服务采购 PIR 供应来源 采购主数据 采购信息记录 ME31K 框架协议 计划协议 采购合同 ME01 供应来源确定 货源清单 MEQ1 供应源确定 配额安排 配额评分 MD04 MD21 MRP 计划文件 需求计划 批量程序 MD01N MD02 MRP Live MD05 MM 物料计划 优化采购 供应源 采购订单 ME2A 供应商确认 采购监控 Flexible Workflow 凭证释放 采购审批 释放策略 实地盘点 物料凭证 货物移动 MIGO 收货 移动类型 已撤回 供应商退货 货物发出 STO 库存转储 转移过账 生产订单 预留 GR/IR MIRO 供应商发票 物流发票校验 OMR2 税码 FI PP SD 实操教程 MRBR OMR6 发票差异 交货成本 后续借记 MI01 实物盘点 盘点差异 公司代码 工厂 组织结构 OMS2 主数据定制 自动科目确定 BP角色 CVI 伙伴确定 编号范围 凭证类型 字段选择 FBN1 OMBT OMC2 会计凭证 OMJJ BOM 委外加工 项目类别L MRKO 供应商寄售 特殊库存K MRKON PIPE Pipeline 特殊库存P ERS MRIS 发票计划 周期性结算 里程碑付款 变更追踪 版本管理 采购凭证 SFTP WebDAV 网盘 飞牛fnOS AMPL HERS MPN 中文教程 库存确定 可用性检查 缺件检查 Output Management 消息确定 输出确定 分割评估 库存计价 评估类别 评估类型 PB00 RM0000 条件技术 采购定价 MM-FI集成 OBYC 库存估价 文本类型 文本采用 EFB EVO MSV SU3 用户参数 发票校验 合同参照 履约保留款 特别总账 预付款 Fiori Launchpad SAP Fiori 应用导航 用户体验 LSMW LTMC Migration Cockpit 数据迁移 BRFplus OPD Output Control My Inbox 审批流程 灵活工作流 SAP PP 外部加工 SAP QM 检验批 质量信息记录 采购收货 SAP PM 维护BOM 维护订单 SAP SD SAP Service 端到端流程 MM模块培训 FI-MM集成 供应商管理 审批配置 FICO入门 SAP FICO 财务配置 供应商税务 预扣税 House Bank 银行对账 客户清账 应收账款 FI控制 验证与替代 印度 GST 税务配置 F110 FBZP EWM入门 SAP EWM 仓库管理 OX14 成本核算 物料评估 后勤配置 物料组 价值更新 数量更新 PP-PI 流程制造 生产计划
联系我们
联系电话:15090125178(微信同号)
电子邮箱:garson_zhang@163.com
站长微信二维码
微信二维码