>  기사  >  위챗 애플릿  >  .NET WeChat 공용 계정 개발(5.0 WeChat 결제) 상세 예시

.NET WeChat 공용 계정 개발(5.0 WeChat 결제) 상세 예시

Y2J
Y2J원래의
2017-05-03 10:31:303476검색

1. 서문

이 기능을 시작하기 전에 가장 먼저 해야 할 일은 이 WeChat 결제를 수행하는 방법, 시작 위치, 시작 위치, 공식 SDK 지침 및 등등, 공식 데모가 있는지, 상사가 준 정보가 완전한지, 적용할 인터페이스가 사용 가능한지 등입니다.

직접 탐색한 끝에 상사의 권유로 이 작업을 완료했습니다. WeChat 결제가 매우 혼란스럽습니다. 제 능력이 부족해서 여기에 요약하겠습니다. .내가 말한 것이 좋지 않은 것이 있으면 양해해 주시기 바랍니다.

2. 개발 전 준비사항.

1.0 WeChat Pay 공식 개발자 문서

2.0 공식 데모 다운로드 c#을 사용하기 때문에 .net 버전을 선택했는데, 이 공식 데모가 전혀 실행되지 않습니다

3.0 공식 데모 실행 솔루션

WeChat Payment 4.0 공식 .net 버전의 함정은 협상할 수 없습니다

5.0 개발 전 WeChat 공개 플랫폼의 일부 구성을 꼭 확인하세요.

3. 🎜>

이러한 준비를 완료한 후 WeChat 결제에는 두 가지 유형이 있다는 것을 알게 되었습니다. 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>

주의 사항:

WeChat JS API는 WeChat 내장 브라우저에서만 사용할 수 있으며 다른 브라우저에서의 호출은 유효하지 않습니다. WeChat은 판매자의 프런트엔드 웹페이지에서 호출할 수 있는 getBrandWCPayRequest 인터페이스를 제공합니다. WeChat은 판매자에게 전화를 걸기 전에 판매자의 결제 기관을 식별합니다. 판매자에게 결제 시작 권한이 있는 경우 결제 프로세스가 시작됩니다. 여기서는 주로 결제 전 인터페이스 호출 규칙을 소개합니다. 아래 결제 상태 메시지 알림 메커니즘을 참조하세요. 인터페이스에 주목해야 합니다. 들어오는 모든 매개변수는 문자열 유형입니다!

getBrandWCPayRequest 매개변수는 표 6-5에 나와 있습니다.

패키지주문 세부정보 확장 문자열은문자열 유형, 4096바이트 미만판매자는 이 문자열에 주문 정보를 구성합니다. 구체적인 구성 방식은 패키지 그룹화 도움말을 참조하세요. 인터페이스 지침에 따라 signTypepaySign

매개변수

이름

필수

형식

설명

appId

공식 계정 아이디

문자열 유형

가맹점에서 결제 권한이 있는 공용 계정을 성공적으로 등록한 후에 얻을 수 있습니다.

timeStamp

timestamp

32바이트 미만의 문자열 유형

판매자가 생성한 1970년 1월 1일 00:00:00부터 현재까지의 초 수, 즉 그리고 마지막으로 문자열 형식으로 변환해야 합니다.

nonceStr

Random string

문자열 유형이며 32바이트 미만

판매자가 생성한 임의의 문자열입니다. >

서명 방법

의 문자열 유형입니다. 매개변수 값은 그림과 같이 "SHA1"

입니다. 현재 SHA1만 지원합니다.

签名

字符串类型

商户将接口列表中的参数按照指定方式迚行签名,签名方式使用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变量能够顺利拿到值,那么我们前台页面的:1572a0d4f3a6a8cd0c7e22edefaeebe0z这里就可以获取到我们要传递的参数,这时候就可以调用微信支付的接口,打开我们的付款页面如图所示:

               //调用微信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 WeChat 공용 계정 개발(5.0 WeChat 결제) 상세 예시의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.