目录
一.前言
二.开发前准备。
三.编码
四.最终开发的效果
五.微信公众号开发系列导航
首页 微信小程序 微信开发 .NET微信公众号开发(5.0微信支付)实例详解

.NET微信公众号开发(5.0微信支付)实例详解

May 03, 2017 am 10:31 AM

一.前言

在开始做这个功能之前,我们要做的第一件事情就是思考,如何做这个微信支付,从哪里开始,从哪里入手,官方的sdk说明什么的,有没有什么官方的demo,还有就是老板给我的一些资料齐全不,那些要申请的接 口什么的都有没有。

经过自己的一些探索,在老板的催促下终于硬着头皮做完了这个,很坑很坑的微信支付,在此做一些总结,希望对你们有所帮助,本人能力有限,如果有什么说的不好,希望大家多多包涵。

二.开发前准备。

  1.0微信支付官方开发者文档

  2.0官方demo下载 我们用c#所以选择.net版本 不过这个官方的demo根本跑步起来

  3.0官方demo运行起来解决方案  

  4.0微信支付官方.net版之坑你没商量

  5.0开发前的微信公众平台的一些配置,请务必认真检查配置.

三.编码

  做好了这些准备工作之后,我们知道微信支付有两种,1.原生态的,2.jsapi直接调用的,我项目中用到的是第二种

  经过自己的一些业务逻辑处理,来到了我们的订单详情页面,现在需要去点击我们的支付按钮去支付,支付页面pay.aspx代码如下,

  前台页面:

<script type="text/javascript">               //调用微信JS api 支付               function jsApiCall()
               {
                   WeixinJSBridge.invoke(                   &#39;getBrandWCPayRequest&#39;,                   <%=wxJsApiParam%>,//josn串                    function (res)
                    {                      if (res.err_msg == "get_brand_wcpay_request:ok")
                       {                           var OrderId=$("#OrderId").val();                           var orderProductName=$("#orderProductName").val();                           var orderMoneySum=$("#orderMoneySum").val();
                            window.location.href="http://www.baidu.aspx?OrderId="+OrderId+"&orderMoneySum="+orderMoneySum+"&orderProductName="+orderProductName;//支付成功后的跳转页面

                        }else
                        {
                          WeixinJSBridge.call(&#39;closeWindow&#39;);
                        }
                         
                     }
                    );
               }

               function callpay()
               {                   if (typeof WeixinJSBridge == "undefined")
                   {                       if (document.addEventListener)
                       {
                           document.addEventListener(&#39;WeixinJSBridgeReady&#39;, jsApiCall, false);
                       }                       else if (document.attachEvent)
                       {
                           document.attachEvent(&#39;WeixinJSBridgeReady&#39;, jsApiCall);
                           document.attachEvent(&#39;onWeixinJSBridgeReady&#39;, jsApiCall);
                       }
                   }                   else
                   {
                       jsApiCall();
                   }
               }               
           </script>


<body>
    <p>
       
       <br />
       <br />
       <br />
       <input  type="hidden" id="OrderId" name="OrderId" value="<%=OrderId %>"/>
       <input  type="hidden" id="orderMoneySum" name="orderMoneySum" value="<%=orderMoneySum %>"/>
       <input  type="hidden" id="orderProductName" name="orderProductName" value="<%=orderProductName %>"/>
       <span class="fLeft" style="font-size:20px;color:Purple">  您确认付款<label style="font-size:25px;color:Red"><%=Money%></label>元...</span>
      <p><button type="button" class="btn-pay" title="确认支付" onclick="callpay()">立即支付</button></p>
    </p>
</body>
</html>
登录后复制

需要注意的是:

微信JS API只能在微信内置浏览器中使用,其他浏览器调用无效。微信提供getBrandWCPayRequest接口供商户前端网页调用,调用之前微信会鉴定商户支付权限,若商户具有调起支付的权限,则将开始支付流程。 这里主要介绍支付前的接口调用规则,支付状态消息通知机制请参加下文。接口需要注意:所有传入参数都是字符串类型!

getBrandWCPayRequest参数如表6-5所示。

参数

名称

必填

格式

说明

appId

公众号id

字符串类型

商户注册具有支付权限的公众号成功后即可获得;

timeStamp

时间戳

字符串类型,32个字节以下

商户生成,从1970年1月1日00:00:00至今的秒数,即当前的时间,且最终需要转换为字符串形式;

nonceStr

随机字符串

字符串类型,32个字节以下

商户生成的随机字符串;

package

订单详情扩展字符串

字符串类型,4096个字节以下

商户将订单信息组成该字符串,具体组成方案参见接口使用说明中package组包帮劣;由商户按照规范拼接后传入;

signType

签名方式

字符串类型,参数取值"SHA1"

按照文档中所示填入,目前仅支持SHA1;

paySign

签名

字符串类型

商户将接口列表中的参数按照指定方式迚行签名,签名方式使用signType中标示的签名方式,具体签名方案参见接口使用说明中签名帮劣;由商户按照规范签名后传入;

表6-5 getBrandWCPayRequest参数

getBrandWCPayRequest返回值如表6-6所示。


返回值

说明

err_msg

get_brand_wcpay_request:ok 支付成功
get_brand_wcpay_request:cancel 支付过程中用户取消
get_brand_wcpay_request:fail 支付失败

表6-6 getBrandWCPayRequest返回值

JS API的返回结果 get_brand_wcpay_request:ok 仅在用户成功完成支付时返回。由于前端交互复杂,get_brand_wcpay_request:cancel 或者 get_brand_wcpay_request:fail 可以统一处理为用户遇到错误或者 主动放弃,不必细化区分。

pay.aspx后台页面代码:

     
          wxJsApiParam { ; ; } 
          Money { ;   OrderId { ;   orderMoneySum { ; ; }
          orderProductName { ; ; }
          Page_Load( (!=  JsApiPay( total_fee = Request[
                        orderMoneySum = ParkName = Request[= ParkName+= Request[ (.IsNullOrWhiteSpace(total_fee)||total_fee==  WxPayException( +  + =.Parse((Convert.ToDouble(total_fee)*= (Convert.ToDouble(jsApiPay.total_fee)/=
                         (Common.OpenId ==   WxPayException(=== jsApiPay.GetJsApiParameters(); +  + 

ex.InnerException.Message +  +  + ex.Message +
登录后复制

在这里需要我们注意的是:jsApiPay.openid = common.GetOpenId();

在支付的时候,我们需要首先获取用户的openId,然而获取用户openId的这个过程我们首先要进行Oauth2认证,在官方的demo中提供了JsApiPay.cs这个核心类库,里面已经有这个GetOpenidAndAccessToken()方法 。我这里是拿过来写成了自己的一个公共帮助类。Common.cs

    /// <summary>
    /// 公共帮助类    /// </summary>
    public class Common
    {        private  HttpContext Context { get; set; }        public static string OpenId = "Openid";        public static string access_token = "access_token";        #region 构造函数        /// <summary>
        /// 构造函数        /// </summary>
        /// <param name="Context"></param>
        public Common(HttpContext context)
        {            this.Context = context;
        } 
        #endregion


        #region 通过code换取AccessToken        /// <summary>
        /// 通过code换取AccessToken        /// </summary>
        public  void GetOpenidAndAccessToken()
        {            if (!string.IsNullOrEmpty(Context.Request.QueryString["code"]))
            {                //获取code码,以获取openid和access_token
                string code = Context.Request.QueryString["code"];                GetOpenidAndAccessTokenFromCode(code);
            }            else
            {                //构造网页授权获取code的URL
                string host = Context.Request.Url.Host;
                string path = Context.Request.Path;                string redirect_uri = HttpUtility.UrlEncode("http://" + host + path);


                WxPayData data = new WxPayData();
                data.SetValue("appid", 

WxPayConfig.APPID);
                data.SetValue("redirect_uri", redirect_uri);
                data.SetValue("response_type", "code");
                data.SetValue("scope", "snsapi_base");
                data.SetValue("state", "STATE" + "#wechat_redirect");                string url = "https://open.weixin.qq.com/connect/oauth2/authorize?" + data.ToUrl();                try
                {                    //触发微信返回code码         
                    Context.Response.Redirect(url);//Redirect函数会抛出ThreadAbortException异常,不用处理这个异常                }                catch (System.Threading.ThreadAbortException ex)
                {
                }
            }
        }        
        #endregion

        #region 通过用户授权获取AccessToken和OpenId        /// <summary>
        /// 通过用户授权获取AccessToken和OpenId        /// </summary>
        /// <param name="code"></param>
        public  void GetOpenidAndAccessTokenFromCode(string code)
        {            try
            {                //构造获取openid及access_token的url
                WxPayData data = new WxPayData();
                data.SetValue("appid", 

WxPayConfig.APPID);
                data.SetValue("secret", 

WxPayConfig.APPSECRET);
                data.SetValue("code", 

code);
                data.SetValue("grant_type", "authorization_code");                string url = "https://api.weixin.qq.com/sns/oauth2/access_token?" + data.ToUrl();                //请求url以获取数据
                string result = HttpService.Get(url);                //保存access_token,用于收货地址获取
                JsonData jd = JsonMapper.ToObject(result);
                access_token = (string)jd["access_token"];                //获取用户openid
                OpenId = (string)jd["openid"];
            }            catch (Exception ex)
            {                throw new WxPayException(ex.ToString());
            }
        } 
        #endregion

        #region 获取OpenId        /// <summary>
        /// 获取OpenId        /// </summary>
        /// <param name="postStr"></param>
        /// <returns></returns>
        public string GetOpenId()
        {
                Common common = new Common(Context);
                common.GetOpenidAndAccessToken();                return OpenId;        } 
        #endregion
    }
登录后复制

 public class JsApiPay
    {        /// <summary>
        /// 保存页面对象,因为要在类的方法中使用Page的Request对象        /// </summary>
        private Page page {get;set;}        /// <summary>
        /// openid用于调用统一下单接口        /// </summary>
        public string openid { get; set; }        /// <summary>
        /// access_token用于获取收货地址js函数入口参数        /// </summary>
        public string access_token { get; set; }        /// <summary>
        /// 商品金额,用于统一下单        /// </summary>
        public int total_fee { get; set; }        /// <summary>
        /// 订单Id        /// </summary>
        public string orderid { get; set; }        /// <summary>
        /// 统一下单接口返回结果        /// </summary>
        public WxPayData unifiedOrderResult { get; set; } 

        public JsApiPay(Page page)
        {            this.page = page;
        }        /**
        * 
        * 网页授权获取用户基本信息的全部过程
        * 详情请参看网页授权获取用户基本信息:http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html
        * 第一步:利用url跳转获取code
        * 第二步:利用code去获取openid和access_token
        * 
        */
        public void GetOpenidAndAccessToken()
        {            if (!string.IsNullOrEmpty(page.Request.QueryString["code"]))
            {                //获取code码,以获取openid和access_token
                string code = page.Request.QueryString["code"];                //Log.Debug(this.GetType().ToString(), "Get code : " + code);                GetOpenidAndAccessTokenFromCode(code);
            }            else
            {                //构造网页授权获取code的URL
                string host = page.Request.Url.Host;                //Log.Debug(this.GetType().ToString(), "host" + host);
                string path = page.Request.Path;                string redirect_uri = HttpUtility.UrlEncode("http://" + host + path);
                

                WxPayData data = new WxPayData();
                data.SetValue("appid", 

WxPayConfig.APPID);
                data.SetValue("redirect_uri", redirect_uri);
                data.SetValue("response_type", "code");
                data.SetValue("scope", "snsapi_base");
                data.SetValue("state", "STATE" + "#wechat_redirect");                string url = "https://open.weixin.qq.com/connect/oauth2/authorize?" + data.ToUrl();
                Log.Debug(this.GetType().ToString(), "Will Redirect to URL : 

" + url);                try
                {                    //触发微信返回code码         
                    page.Response.Redirect(url);//Redirect函数会抛出ThreadAbortException异常,不用处理这个异常                }                catch(System.Threading.ThreadAbortException ex)
                {
                }
            }
        }        /**
        * 
        * 通过code换取网页授权access_token和openid的返回数据,正确时返回的JSON数据包如下:
        * {
        *  "access_token":"ACCESS_TOKEN",
        *  "expires_in":7200,
        *  "refresh_token":"REFRESH_TOKEN",
        *  "openid":"OPENID",
        *  "scope":"SCOPE",
        *  "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
        * }
        * 其中access_token可用于获取共享收货地址
        * openid是微信支付jsapi支付接口统一下单时必须的参数
        * 更详细的说明请参考网页授权获取用户基本信息:http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html
        * @失败时抛异常WxPayException        */
        public void GetOpenidAndAccessTokenFromCode(string code)
        {            try
            {                //构造获取openid及access_token的url
                WxPayData data = new WxPayData();
                data.SetValue("appid", 

WxPayConfig.APPID);
                data.SetValue("secret", 

WxPayConfig.APPSECRET);
                data.SetValue("code", 

code);
                data.SetValue("grant_type", "authorization_code");                string url = "https://api.weixin.qq.com/sns/oauth2/access_token?" + data.ToUrl();                //请求url以获取数据
                string result = HttpService.Get(url);                //Log.Debug(this.GetType().ToString(), "GetOpenidAndAccessTokenFromCode response : " + result);                //保存access_token,用于收货地址获取
                JsonData jd = JsonMapper.ToObject(result);
                access_token = (string)jd["access_token"];                //获取用户openid
                openid = (string)jd["openid"];                //Log.Debug(this.GetType().ToString(), "Get openid : " + openid);                //Log.Debug(this.GetType().ToString(), "Get access_token : " + access_token);            }            catch (Exception ex)
            {
                Log.Error(this.GetType().ToString(), ex.ToString());                throw new WxPayException(ex.ToString());
            }
        }        /**
         * 调用统一下单,获得下单结果
         * @return 统一下单结果
         * @失败时抛异常WxPayException         */
        public WxPayData GetUnifiedOrderResult()
        {            //统一下单
            WxPayData data = new WxPayData();
            data.SetValue("body", "test");            //data.SetValue("attach", "test");
            data.SetValue("out_trade_no", 

WxPayApi.GenerateOutTradeNo());
            data.SetValue("total_fee", 

total_fee);
            data.SetValue("time_start", DateTime.Now.ToString("yyyyMMddHHmmss"));
            data.SetValue("time_expire", DateTime.Now.AddMinutes(10).ToString("yyyyMMddHHmmss"));            //data.SetValue("goods_tag", "test");
            data.SetValue("trade_type", "JSAPI");
            data.SetValue("openid", 

openid);
            data.SetValue("orderid", 

orderid);

            WxPayData result = WxPayApi.UnifiedOrder(data);            if (!result.IsSet("appid") || !result.IsSet("prepay_id") || result.GetValue("prepay_id").ToString() == "")
            {
                Log.Error(this.GetType().ToString(), "UnifiedOrder response 

error!");                throw new WxPayException("UnifiedOrder response error!");
            }

            unifiedOrderResult = result;            return result;
        }        public WxPayData GetUnifiedOrderResult(string body)
        {            //统一下单
            WxPayData data = new WxPayData();
            data.SetValue("body", body);            //data.SetValue("attach", "test");
            data.SetValue("out_trade_no", 

WxPayApi.GenerateOutTradeNo());
            data.SetValue("total_fee", 

total_fee);            //data.SetValue("time_start", DateTime.Now.ToString("yyyyMMddHHmmss"));            //data.SetValue("time_expire", DateTime.Now.AddMinutes(10).ToString("yyyyMMddHHmmss"));            //data.SetValue("goods_tag", "test");
            data.SetValue("trade_type", "JSAPI");
            data.SetValue("openid", 

openid);


            WxPayData result = WxPayApi.UnifiedOrder(data);            if (!result.IsSet("appid") || !result.IsSet("prepay_id") || result.GetValue("prepay_id").ToString() == "")
            {
                Log.Error(this.GetType().ToString(), "UnifiedOrder response 

error!");                throw new WxPayException("UnifiedOrder response error!");
            }

            unifiedOrderResult = result;            return result;
        }        /**
        *  
        * 从统一下单成功返回的数据中获取微信浏览器调起jsapi支付所需的参数,
        * 微信浏览器调起JSAPI时的输入参数格式如下:
        * {
        *   "appId" : "wx2421b1c4370ec43b",     //公众号名称,由商户传入     
        *   "timeStamp":" 1395712654",         //时间戳,自1970年以来的秒数     
        *   "nonceStr" : "e61463f8efa94090b1f366cccfbbb444", //随机串     
        *   "package" : "prepay_id=u802345jgfjsdfgsdg888",     
        *   "signType" : "MD5",         //微信签名方式:    
        *   "paySign" : "70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信签名 
        * }
        * @return string 微信浏览器调起JSAPI时的输入参数,json格式可以直接做参数用
        * 更详细的说明请参考网页端调起支付API:http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7
        * 
        */
        public string GetJsApiParameters()
        {

            WxPayData jsApiParam = new WxPayData();
            jsApiParam.SetValue("appId", unifiedOrderResult.GetValue

("appid"));
            jsApiParam.SetValue("timeStamp", WxPayApi.GenerateTimeStamp());
            jsApiParam.SetValue("nonceStr", WxPayApi.GenerateNonceStr());
            jsApiParam.SetValue("package", "prepay_id=" + unifiedOrderResult.GetValue("prepay_id"));
            jsApiParam.SetValue("signType", "MD5");
            jsApiParam.SetValue("paySign", jsApiParam.MakeSign());            string parameters = jsApiParam.ToJson();            return parameters;
        }        /**
        * 
        * 获取收货地址js函数入口参数,详情请参考收货地址共享接口:http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?

chapter=7_9
        * @return string 共享收货地址js函数需要的参数,json格式可以直接做参数使用        */
        public string GetEditAddressParameters()
        {            string parameter = "";            try
            {                string host = page.Request.Url.Host;                string path = page.Request.Path;                string queryString = page.Request.Url.Query;                //这个地方要注意,参与签名的是网页授权获取用户信息时微信后台回传的完整url
                string url = "http://" + 

host + path + queryString;                //构造需要用SHA1算法加密的数据
                WxPayData signData = new WxPayData();
                signData.SetValue("appid",WxPayConfig.APPID);
                signData.SetValue("url", 

url);
                signData.SetValue("timestamp",WxPayApi.GenerateTimeStamp());
                signData.SetValue("noncestr",WxPayApi.GenerateNonceStr());
                signData.SetValue("accesstoken",access_token);                string param = signData.ToUrl();

                Log.Debug(this.GetType().ToString(), "SHA1 encrypt param : 

" + param);                //SHA1加密
                string addrSign = FormsAuthentication.HashPasswordForStoringInConfigFile(param, "SHA1");
                Log.Debug(this.GetType().ToString(), "SHA1 encrypt result : 

" + addrSign);                //获取收货地址js函数入口参数
                WxPayData afterData = new WxPayData();
                afterData.SetValue("appId",WxPayConfig.APPID);
                afterData.SetValue("scope","jsapi_address");
                afterData.SetValue("signType","sha1");
                afterData.SetValue("addrSign",addrSign);
                afterData.SetValue("timeStamp",signData.GetValue("timestamp"));
                afterData.SetValue("nonceStr",signData.GetValue("noncestr"));                //转为json格式
                parameter = afterData.ToJson();
                Log.Debug(this.GetType().ToString(), "Get EditAddressParam : 

" + parameter);
            }            catch (Exception ex)
            {
                Log.Error(this.GetType().ToString(), ex.ToString());                throw new WxPayException(ex.ToString());
            }            return parameter;
        }
    }
登录后复制

JsApiPay

微信支付协议接口数据类WxPayData.cs官方都有相应的代码.

 /// <summary>
    /// 微信支付协议接口数据类,所有的API接口通信都依赖这个数据结构,    /// 在调用接口之前先填充各个字段的值,然后进行接口通信,    /// 这样设计的好处是可扩展性强,用户可随意对协议进行更改而不用重新设计数据结构,    /// 还可以随意组合出不同的协议数据包,不用为每个协议设计一个数据包结构    /// </summary>
    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)
            {
                Log.Error(this.GetType().ToString(), "WxPayData数据为空!");                throw new WxPayException("WxPayData数据为空!");
            }            string xml = "<xml>";            foreach (KeyValuePair<string, object> pair in m_values)
            {                //字段值不能为null,会影响后续流程
                if (pair.Value == null)
                {
                    Log.Error(this.GetType().ToString(), "WxPayData内部含有值

为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类型不能含有其他数据类型                {
                    Log.Error(this.GetType().ToString(), "WxPayData字段数据类

型错误!");                    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))
            {
                Log.Error(this.GetType().ToString(), "将空的xml串转换为

WxPayData不合法!");                throw new WxPayException("将空的xml串转换为WxPayData不合法!");
            }

            XmlDocument xmlDoc = new XmlDocument();
            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"] != "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)
                {
                    Log.Error(this.GetType().ToString(), "WxPayData内部含有值

为null的字段!");                    throw new WxPayException("WxPayData内部含有值为null的字段!");
                }                if (pair.Key != "sign" && pair.Value.ToString() != "")
                {
                    buff += pair.Key + "=" + pair.Value + "&";
                }
            }
            buff = buff.Trim(&#39;&&#39;);            return buff;
        }        /**
        * @Dictionary格式化成Json
         * @return json串数据        */
        public string ToJson()
        {            string jsonStr = JsonMapper.ToJson(m_values);            return jsonStr;
        }        /**
        * @values格式化成能在Web页面上显示的结果(因为web页面上不能直接输出xml格式的字符串)        */
        public string ToPrintStr()
        {            string str = "";            foreach (KeyValuePair<string, object> pair in m_values)
            {                if (pair.Value == null)
                {
                    Log.Error(this.GetType().ToString(), "WxPayData内部含有值

为null的字段!");                    throw new WxPayException("WxPayData内部含有值为null的字段!");
                }

                str += string.Format("{0}={1}<br>", pair.Key, pair.Value.ToString());
            }
            Log.Debug(this.GetType().ToString(), "Print in Web Page : 

" + str);            return str;
        }        /**
        * @生成签名,详见签名生成算法
        * @return 签名, sign字段不参加签名        */
        public string MakeSign()
        {            //转url格式
            string str = ToUrl();            //在string后加入API KEY
            str += "&key=" + WxPayConfig.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"))
            {
               Log.Error(this.GetType().ToString(), "WxPayData签名存在但不合法

!");               throw new WxPayException("WxPayData签名存在但不合法!");
            }            //如果设置了签名但是签名为空,则抛异常
            else if(GetValue("sign") == null || GetValue("sign").ToString() == "")
            {
                Log.Error(this.GetType().ToString(), "WxPayData签名存在但不合

法!");                throw new WxPayException("WxPayData签名存在但不合法!");
            }            //获取接收到的签名
            string return_sign = GetValue("sign").ToString();            //在本地计算新的签名
            string cal_sign = MakeSign();            if (cal_sign == return_sign)
            {                return true;
            }

            Log.Error(this.GetType().ToString(), "WxPayData签名验证错误!");            throw new WxPayException("WxPayData签名验证错误!");
        }        /**
        * @获取Dictionary        */
        public SortedDictionary<string, object> GetValues()
        {            return m_values;
        }
    }
登录后复制

WxPayData

配置文件信息

    /**
    *     配置账号信息    */
    public class WxPayConfig
    {        //=======【基本信息设置】=====================================
        /* 微信公众号信息配置
        * APPID:绑定支付的APPID(必须配置)
        * MCHID:商户号(必须配置)
        * KEY:商户支付密钥,参考开户邮件设置(必须配置)
        * APPSECRET:公众帐号secert(仅JSAPI支付的时候需要配置)        */
        public const string APPID = "wx14e3e56f3";        public const string MCHID = "12352";        public const string KEY = "BB6BE71D7CED49A79409C9";        public const string APPSECRET = "76eb33f66129692da1624f1";        //=======【证书路径设置】===================================== 
        /* 证书路径,注意应该填写绝对路径(仅退款、撤销订单时需要)        */
        public const string SSLCERT_PATH = "cert/apiclient_cert.p12";        public const string SSLCERT_PASSWORD = "123502";        //=======【支付结果通知url】===================================== 
        /* 支付结果通知回调url,用于商户接收支付结果        */
        public const string NOTIFY_URL = "http://www.baidu.com/ResultPay.aspx";        //=======【商户系统后台机器IP】===================================== 
        /* 此参数可手动配置也可在程序中自动获取        */
        public const string IP = "150.24.91.151";        //=======【代理服务器设置】===================================
        /* 默认IP和端口号分别为0.0.0.0和0,此时不开启代理(如有需要才设置)        */
        public const string PROXY_URL = "http://10.152.18.220:8080";        //=======【上报信息配置】===================================
        /* 测速上报等级,0.关闭上报; 1.仅错误时上报; 2.全量上报        */
        public const int REPORT_LEVENL = 1;        //=======【日志级别】===================================
        /* 日志等级,0.不输出日志;1.只输出错误信息; 2.输出错误和正常信息; 3.输出错误信息、正常信息和调试信息        */
        public const int LOG_LEVENL =3;
    }
登录后复制

WxPayConfig

接着我们在看2行关键的代码:

                            WxPayData unifiedOrderResult == jsApiPay.GetJsApiParameters();
登录后复制

此时如果wxJsApiParam变量能够顺利拿到值,那么我们前台页面的:<%=wxJsApiParam%>z这里就可以获取到我们要传递的参数,这时候就可以调用微信支付的接口,打开我们的付款页面如图所示:

               //调用微信JS api 支付               function jsApiCall()
               {
                   WeixinJSBridge.invoke(                   &#39;getBrandWCPayRequest&#39;,                   <%=wxJsApiParam%>,//josn串                    function (res)
                    {                      if (res.err_msg == "get_brand_wcpay_request:ok")
                       {                           var OrderId=$("#OrderId").val();                           var orderProductName=$("#orderProductName").val();                           var orderMoneySum=$("#orderMoneySum").val();                             window.location.href="http://www.baodu.com/PaySkip.aspx?OrderId="+OrderId+"&orderMoneySum="+orderMoneySum+"&orderProductName="+orderProductName;

                        }else
                        {
                          WeixinJSBridge.call(&#39;closeWindow&#39;);
                        }
                         
                     }
                    );
               }
登录后复制

(JsApiPay.cs)得到下单结果:

        public WxPayData GetUnifiedOrderResult(string body)
        {            //统一下单
            WxPayData data = new WxPayData();
            data.SetValue("body", 

body);
            data.SetValue("out_trade_no", 

WxPayApi.GenerateOutTradeNo());
            data.SetValue("total_fee", 

total_fee);
            data.SetValue("trade_type", "JSAPI");
            data.SetValue("openid", 

openid);            WxPayData result = WxPayApi.UnifiedOrder(data);            if (!result.IsSet("appid") || !result.IsSet("prepay_id") || result.GetValue("prepay_id").ToString() == "")
            {
                Log.Error(this.GetType().ToString(), "UnifiedOrder response 

error!");                throw new WxPayException("UnifiedOrder response error!");
            }

            unifiedOrderResult = result;            return result;
        }
登录后复制

(WxPayApi.cs)统一下单接口:

        /**
        * 
        * 统一下单
        * @param WxPaydata inputObj 提交给统一下单API的参数
        * @param int timeOut 超时时间
        * @throws WxPayException
        * @return 成功时返回,其他抛异常        */
        public static WxPayData UnifiedOrder(WxPayData inputObj, int timeOut = 

6)
        {            string url = "https://api.mch.weixin.qq.com/pay/unifiedorder";            //检测必填参数
            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为必填参数!");
            }            //异步通知url未设置,则使用配置文件中的url
            if (!inputObj.IsSet("notify_url"))
            {
                inputObj.SetValue("notify_url", 

WxPayConfig.NOTIFY_URL);//异步通知url            }

            inputObj.SetValue("appid", WxPayConfig.APPID);//公众账号ID
            inputObj.SetValue("mch_id", WxPayConfig.MCHID);//商户号
            inputObj.SetValue("spbill_create_ip", WxPayConfig.IP);//终端ip              
            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);
            var end = DateTime.Now;            int timeCost = (int)((end - start).TotalMilliseconds);

            WxPayData result = new WxPayData();
            result.FromXml(response);

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

            return result;
        }
登录后复制

四.最终开发的效果

五.微信公众号开发系列导航

1.0初始微信公众号

2.0创建自定义菜单

3.0查询自定义菜单

4.0公众号消息处理

5.0微信支付

6.0模板消息

以上是.NET微信公众号开发(5.0微信支付)实例详解的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

微信支付密码忘记了怎么找回 微信支付密码忘记了怎么找回 Feb 23, 2024 pm 09:40 PM

微信中用户可以输入支付密码来购物,那么支付密码忘记了怎么找回呢?用户们需要我的-服务-钱包-支付设置-忘记支付密码就能恢复。这篇支付密码忘记找回方法介绍就能告诉大家具体的操作方法,下面就是详细介绍,赶紧看看吧!微信使用教程微信支付密码忘记了怎么找回答:我的-服务-钱包-支付设置-忘记支付密码具体方法:1、首先点击我的。2、点击里面的服务。3、点击里面的钱包。4、找到支付设置。5、点击忘记支付密码。6、输入自己的信息验证。7、然后输入新的支付密码就可以更改了。

微信支付密码忘记了怎么办 微信支付密码忘记了怎么办 Jan 08, 2024 pm 05:02 PM

微信支付密码忘记了的解决办法:1、打开微信APP,点击右下角的”我“,进入个人中心页面;2、在个人中心页面中,点击“支付”,进入支付页面;3、在支付页面中,点击右上角的“…”,进入支付管理页面;4、在支付管理页面中,找到并点击“忘记支付密码”;5、按照页面提示,输入个人信息进行身份验证,验证成功后,可以选择“刷脸找回”或“验证银行卡信息找回”的方式来找回密码等等。

美团外卖怎么设置微信支付 设置微信付款的方法 美团外卖怎么设置微信支付 设置微信付款的方法 Mar 12, 2024 pm 10:34 PM

  美团外卖app软件内提供的美食小吃店铺非常多,而且所有的手机用户都是通过账号登录的。添加个人的收货地址以及联系电话,享受最便捷的外卖服务。打开软件首页,即可输入商品关键词,在线搜索就能找到相对应的商品结果,上下滑动选购下单即可,平台也会根据用户提供的配送地址,推荐周边附近数十家好评超高的店铺,还能设置不同的支付方式,一键下单完成订单即可,骑手第一时间安排配送速度非常快,还有不同金额的外卖红包领取使用,现在小编在线详细为美团外卖用户们带来设置微信付款的方法。  1选择好商品后,提交订单,点击立

闲鱼可以用微信支付吗  改成微信付款的方法 闲鱼可以用微信支付吗 改成微信付款的方法 Mar 12, 2024 pm 12:19 PM

  大家没事的时候,都是会选择逛逛闲鱼这一平台的,大家都能够发现这一平台上,是有着大量的一些商品的存在,都能够让大家看到各种各样的的一些二手的宝贝,虽然是二手的产品,但是这一些产品的质量,绝对都是没有任何的问题,所以大家都能够放心的选购,价格都是特别的实惠,都还是能让大家面对面的与这一些卖家们进行交流沟通,进行一些讲价的操作,完全都是可以的,只要大家谈的妥当的话,那么你们就能够选择进行交易,且大家在这里付款的时候,想要进行微信付款,但是好像平台上是不允许,具体情况如何,跟着小编一起来看看吧。闲鱼

微信支付成功后能马上取消吗 微信支付成功后能马上取消吗 Nov 29, 2023 pm 02:19 PM

微信支付成功后不能马上取消。退款通常需要满足以下条件:1、商户的退款政策,商户会制定自己的退款政策,包括退款的时间窗口、退款金额和退款方式等;2、支付时间,退款通常需要在一定的时间范围内进行申请,超过该时间范围可能无法退款;3、商品或服务状态,如果用户已经收到了商品或享受了服务,商户可能会要求用户将商品退回或提供相应的证明;4、退款流程等等。

微信支付申请退款的步骤分享 微信支付申请退款的步骤分享 Mar 25, 2024 pm 06:31 PM

1、首先我们需要打开手机上的微信APP,然后点击登录微信账号,这样就进入了微信的首页。2、在微信首页点击右下角的【我】按钮,再选择【支付】选项,我们点击进入支付页面。3、进入【支付】页面后点击【钱包】选项进入,在【钱包】页面点击右上角的【账单】。

阿里巴巴怎么用微信付款_阿里巴巴1688用微信支付方法 阿里巴巴怎么用微信付款_阿里巴巴1688用微信支付方法 Mar 20, 2024 pm 05:51 PM

阿里巴巴1688是采购批发网,里面的东西要比淘宝便宜很多。那么阿里巴巴怎么用微信付款呢?小编整理了一些相关内容分享给大家,有需要的朋友可以来看看哦。阿里巴巴怎么用微信付款答案:暂不能使用微信付款;1、我们在购买商品的页面中我们点击其中的【更换支付方式】2、然后在弹出的页面中我们可以到只有【支付宝、分阶段付款、收银台】可以选择;

滴滴出行怎么设置微信支付 设置微信支付的方法 滴滴出行怎么设置微信支付 设置微信支付的方法 Mar 13, 2024 pm 01:22 PM

  滴滴出行app为大家日常出行提供更多方便,想去哪里就去那里,而且所有的滴滴车辆都是随叫随到的,再也不需要焦急等待了,数十个打车红包免费领,出行速度更快。打开软件首页,根据个人的行程安排,输入出发点以及目的地,正下方不同价位的车辆自由选择,一键下单发布行程出去,滴滴司机都是秒接单的,以最快的速度到达指定地点,上车前核对手机号即可,当然支付车费的方式非常多,微信支付宝都可以,但大家通常都是用微信,一键设置支付轻松搞定,现在小编在线仔细一一为滴滴出行用户们带来设置微信支付的方法。  1、我们在手机

See all articles