好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

C# MVC 微信支付教程系列之公众号支付代码

今天,我们接着讲微信支付的系列教程,前面,我们讲了这个微信红包和扫码支付。现在,我们讲讲这个公众号支付。公众号支付的应用环境常见的用户通过公众号,然后再通过公众号里面的菜单链接,进入公众号的商城,然后在里面完成购买和支付功能,我们可以看看官方对这个公众号支付的场景的解释,链接:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1,通过这个官方的解释,那我们大概清楚这个公众号的用途了,下面,我就说说,做这个公众号支付的准备工作有哪些了。

 1、下载微信web开发者工具,工具的使用方式,也看链接,地址:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455784140&token=&lang=zh_cn

  2、配置[微信支付]环境,如下图:

3、授权获取用户信息,如下图:

 下面开始,一步一步往下走。

 一、我们先开发程序,首先,新建一个mvc工程(asp.net的话,官方给的demo就是asp.net的,可以下载来参考::https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1),名为:微信支付之公众号支付,如下图:

 

然后右键项目,我们修改一下属性,如下图:

然后我们再把程序自动生成的homecontroller.cs和view里面的删掉,再新建一个homecontroller.cs和添加view,代码如下:

?

using system;

using system.collections.generic;

using system.linq;

using system.web;

using system.web.mvc;

 

namespace web.controllers

{

  public class homecontroller : controller

  {

   // get: home

   public actionresult index()

   {

    return view();

   }

  }

}

view代码:

?

@{

  layout = null;

}

 

<!doctype html>

 

< html >

< head >

  < meta name = "viewport" content = "width=device-width" />

  < title >index</ title >

</ head >

< body >

  < div >

  </ div >

</ body >

</ html >

嗯,没错,目前还是空的,现在我们开始写前台,代码如下(我先贴上代码,后续再解释为啥这么做,因为如果一步步的写下去,按照前面两个的篇幅来,我觉得都可以开课了,所以,我先上代码,然后再一步步解释。):

?

@{

  layout = null ;

}

 

<!doctype html>

 

<html>

<head>

  <meta name= "viewport" content= "width=device-width" />

  <title>电表充值服务</title>

  <link href= "~/scripts/jquery-easyui-1.4.5/themes/bootstrap/easyui.css" rel= "stylesheet" />

  <link href= "~/scripts/jquery-easyui-1.4.5/themes/mobile.css" rel= "stylesheet" />

  <link href= "~/scripts/jquery-easyui-1.4.5/themes/icon.css" rel= "stylesheet" />

  <style type= "text/css" >

   body{

    margin:0;

    padding:0;

   }

   .logo {

    width: 100%;

    height: 70px;

    background: url(/images/elelogo.png) 0 0 no-repeat;

    background-size: 100% 100%;

    padding: 0;

    margin: 0;

   }

 

   .line {

    width: 100%;

    float: left;

    height: auto;

    text-align: center;

    margin-top: 10px;

   }

 

   .linetext {

    width: 100%;

    float: left;

    height: auto;

    text-indent: 5%;

    text-align: left;

    font-size: x-large;

    margin: 0;

   }

 

   . function {

    height: 60pt;

    line-height: 60pt;

    width: 45%;

    float: left;

    border-radius: 10px;

    background-color: #990000;

    margin-left: 8pt;

   }

 

   .title {

    font-family: "微软雅黑" ;

    font-size: x-large;

    color: white;

   }

 

   a {

    text-decoration: none;

    color: white;

   }

 

   input {

    vertical-align: central;

   }

 

   label {

    vertical-align: central;

   }

 

   .lbblock {

    border: 1px solid #808080;

    background-color: grey;

    width: 90%;

    margin-left: 5%;

    font-size: x-large;

    border-radius: 10px;

    text-align: left;

    text-indent: 10pt;

    height: 30pt;

    padding-top: 5pt;

   }

 

   .btn {

    width: 90%;

    height: 35pt;

    font-size: x-large;

    background-color: #990000;

    color: white;

    background: url(/images/red.png) 0 0 repeat;

    border: none;

    border-radius: 10px;

    margin: 10px 0 0 0;

   }

 

   .input {

    height: 30pt;

    width: 90%;

    font-size: x-large;

    border-radius: 10px;

    margin: 0;

    padding: 0;

   }

  </style>

 

</head>

<body>

  <div class= "logo" >

  </div>

  <form id= "chargeform" > 

   <div class= "line" >

    <div class= "linetext" >

     充值金额:

    </div>

   </div>

   <div class= "line" >

    <input type= "number" id= "chargeval" name= "chargeval" class= "input" placeholder= "单位:元" />

   </div> 

  </form>

  <div class= "line" >

   <input type= "button" class= "btn" value= "立即充值" onclick= "fcharge()" style= "margin-top: 20px;" />

  </div>

  <div class= "line" >

   <input type= "button" id= "btnhome" class= "btn" value= "返回主页" onclick= "fbackhome()" />

  </div>

  <script src= "~/scripts/jquery-easyui-1.4.5/jquery.min.js" ></script>

  <script src= "~/scripts/jquery-easyui-1.4.5/jquery.easyui.min.js" ></script>

  <script src= "~/scripts/jquery-easyui-1.4.5/jquery.easyui.mobile.js" ></script>

  <script src= "~/scripts/jquery-easyui-1.4.5/easyloader.js" ></script>

  <script type= "text/javascript" >

   $( function () {

    var vcode = getquerystring( "code" );

    if (vcode != "" && vcode != null ) {

     //alert(vcode);

     $.ajax({

      type: 'post' ,

      data: {

       code: vcode

      },

      url: '/home/getwxinfo' ,

      success: function (sjson) {

       //alert(sjson);

       //var vdata = json.stringify(sjson);

       //alert(vdata);

       $.messager.show({

        title: '提示' ,

        msg: '欢迎您来到微信端充值中心。'

       });

      }

     })

    }

    else {

     $.ajax({

      type: 'post' ,

      url: '/home/getcode' ,

      success: function (sjson) {

       //alert(sjson);

       location.href = sjson;

      }

     })

    }

   })

   //获取url的参数

   function getquerystring(name) {

    var reg = new regexp( "(^|&)" + name + "=([^&]*)(&|$)" , "i" );

    var r = window.location.search.substr(1).match(reg);

    if (r != null ) return unescape(r[2]); return null ;

   }

 

 

 

 

 

   //初始化微信支付环境

   function fcharge() {

    if ( typeof weixinjsbridge == "undefined" ) {

     if (document.addeventlistener) {

      document.addeventlistener( 'weixinjsbridgeready' , onbridgeready, false );

     } else if (document.attachevent) {

      document.attachevent( 'weixinjsbridgeready' , onbridgeready);

      document.attachevent( 'onweixinjsbridgeready' , onbridgeready);

     }

    } else {

     fpostcharge();

    }

   }

   //提交充值数据

   function fpostcharge() {

    var vchargeval = $( "#chargeval" ).val();

    vchargeval = parsefloat(vchargeval);

    if (vchargeval > 0) {

     $.messager.progress({

      title: "" ,

      msg: "正在调用微信支付接口,请稍后..."

     });

     $.ajax({

      type: "post" ,

      data: "totalfee=" + vchargeval,

      url: "/home/meterrecharge" ,

      success: function (json) {

       $.messager.progress( 'close' ); //记得关闭

       //var json = eval("(" + msg + ")");//转换后的json对象

       onbridgeready(json);

      },

      error: function () {

       $.messager.progress( 'close' ); //记得关闭

       $.messager.alert( "提示" , '调用微信支付模块失败,请稍后再试。' , 'info' )

      }

     })

    }

    else {

     alert( "房间名或者充值金额不可以为空或者为负数,请确认后再试." )

    }

   }

   //调用微信支付模块

   function onbridgeready(json) {

    weixinjsbridge.invoke(

    'getbrandwcpayrequest' , {

     "appid" : json.appid,  //公众号名称,由商户传入

     "timestamp" : json.timestamp,   //时间戳,自1970年以来的秒数

     "noncestr" : json.noncestr, //随机串

     "package" : json.packagevalue,

     "signtype" : "md5" ,   //微信签名方式:

     "paysign" : json.paysign //微信签名

    },

    function (res) {

     if (res.err_msg == "get_brand_wcpay_request:ok" ) {

      //alert("支付成功,请稍后查询余额,如有疑问,请联系管理员.");

      falreadypay();

     }  // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。

    }

    );

   }

   function fbackhome() {

    location.href = "/" ;

   }

  </script>

</body>

</html>

后台代码如下:

?

using system;

using system.collections.generic;

using system.linq;

using system.web;

using system.web.mvc;

using web.models;

using wxpayapi;

 

namespace web.controllers

{

  public class homecontroller : controller

  {

   jsapipay jsapipay = new jsapipay();

   // get: home

   public actionresult index()

   {

    if (session[ "openid" ] == null )

    {

     try

     {

      //调用【网页授权获取用户信息】接口获取用户的openid和access_token

      getopenidandaccesstoken();

 

     }

     catch (exception ex)

     {

      //response.write(ex.tostring());

      //throw;

     }

    }

    return view();

   }

 

 

   /**

   *

   * 网页授权获取用户基本信息的全部过程

   * 详情请参看网页授权获取用户基本信息:http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html

   * 第一步:利用url跳转获取code

   * 第二步:利用code去获取openid和access_token

   *

   */

   public void getopenidandaccesstoken()

   {

    if (session[ "code" ] != null )

    {

     //获取code码,以获取openid和access_token

     string code = session[ "code" ].tostring();

     log.debug( this .gettype().tostring(), "get code : " + code);

     jsapipay.getopenidandaccesstokenfromcode(code);

    }

    else

    {

     //构造网页授权获取code的url

     string host = request.url.host;

     string path = request.path;

     string redirect_uri = httputility.urlencode( "http://" + host + path);

     //string redirect_uri = httputility.urlencode("http://gzh.lmx.ren");

     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);

     session[ "url" ] = url;   

    }

   }

 

 

   /// <summary>

   /// 获取code

   /// </summary>

   /// <returns></returns>

   [httppost]

   public actionresult getcode()

   {

    object objresult = "" ;

    if (session[ "url" ] != null )

    {

     objresult = session[ "url" ].tostring();

    }

    else

    {

     objresult = "url为空。" ;

    }

    return json(objresult);

   }

 

   /// <summary>

   /// 通过code换取网页授权access_token和openid的返回数据

   /// </summary>

   /// <returns></returns>

   [httppost]

   public actionresult getwxinfo()

   {

    object objresult = "" ;

    string strcode = request.form[ "code" ];

    if (session[ "access_token" ] == null || session[ "openid" ] == null )

    {

     jsapipay.getopenidandaccesstokenfromcode(strcode);

    }

    string straccess_token = session[ "access_token" ].tostring();

    string stropenid = session[ "openid" ].tostring();

    objresult = new { openid = stropenid, access_token = straccess_token };

    return json(objresult);

   }

 

 

 

 

   /// <summary>

   /// 充值

   /// </summary>

   /// <returns></returns>

   [httppost]

   public actionresult meterrecharge()

   {

    object objresult = "" ;

    string strtotal_fee = request.form[ "totalfee" ];

    string strfee = ( double .parse(strtotal_fee) * 100).tostring();

 

    //若传递了相关参数,则调统一下单接口,获得后续相关接口的入口参数

    jsapipay.openid = session[ "openid" ].tostring();

    jsapipay.total_fee = int .parse(strfee);

 

    //jsapi支付预处理

    try

    {

     string strbody = "南宫萧尘微信支付" ; //商品描述

     wxpaydata unifiedorderresult = jsapipay.getunifiedorderresult(strbody);

     wxpaydata wxjsapiparam = jsapipay.getjsapiparameters(); //获取h5调起js api参数,注意,这里引用了官方的demo的方法,由于原方法是返回string的,所以,要对原方法改为下面的代码,代码在下一段

 

     modelfororder aorder = new modelfororder()

     {

      appid = wxjsapiparam.getvalue( "appid" ).tostring(),

      noncestr = wxjsapiparam.getvalue( "noncestr" ).tostring(),

      packagevalue = wxjsapiparam.getvalue( "package" ).tostring(),

      paysign = wxjsapiparam.getvalue( "paysign" ).tostring(),

      timestamp = wxjsapiparam.getvalue( "timestamp" ).tostring(),

      msg = "成功下单,正在接入微信支付."

     };

     objresult = aorder;

    }

    catch (exception ex)

    {

     modelfororder aorder = new modelfororder()

     {

      appid = "" ,

      noncestr = "" ,

      packagevalue = "" ,

      paysign = "" ,

      timestamp = "" ,

      msg = "下单失败,请重试,多次失败,请联系管理员."

     };

     objresult = aorder;

    }

    return json(objresult);

   }

 

 

  }

}

这里就是上面修改了的代码,童鞋们请注意

?

/**

*

* 从统一下单成功返回的数据中获取微信浏览器调起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 wxpaydata getjsapiparameters()

{

  log.debug( this .gettype().tostring(), "jsapipay::getjsapiparam is processing..." );

 

  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();

  log.debug( this .gettype().tostring(), "get jsapiparam : " + parameters);

  return jsapiparam;

}

modelfororder类的代码:

?

using system;

using system.collections.generic;

using system.linq;

using system.web;

 

namespace web.models

{

  public class modelfororder

  {

   public string appid { get ; set ; }

   public string timestamp { get ; set ; }

   public string noncestr { get ; set ; }

   public string packagevalue { get ; set ; }

   public string paysign { get ; set ; }

 

   public string msg { get ; set ; }

  }

}

还有一个地方需要注意,修改一下的就是这里wxlib/business/jsapipay.cs,如下图:

最后,把程序发布出来,这次咱们把web发布在http://gzh.lmx.ren上 ,然后再把接口权限,改为这样的,如下图:

注意,这里面的域名和上面我们发布的域名要一致。 

除此以外,我们还需要改这里:

就是一定要授权这里,否则,支付的时候,会提示其他错误,具体,我就不测试了。

另外,这里其实已经完成了这个公众号的支付的流程了,但是,我们页面上,会友善的提醒(其实不友善,提示是红色的,在头部,提示别输入密码什么),这是因为,我们还没把咱们这个http://gzh.lmx.ren域名设置为安全域名,设置之后,就不会在提示了。设置方法如下图:

在这里面加入咱们的域名,就完美了。。。

 我的代码都尽量精简,多余的,我都会丢掉,就是为了避免混淆视听。如果代码里面,有写的不清楚的,可以私信问我,或群里来问我,群号在文章末端。

 现在,我开始一一解释我上面的做法。

首先,在后端,页面加载的时候,他会先执行

?

public actionresult index()

   {

    if (session[ "openid" ] == null )

    {

     try

     {

      //调用【网页授权获取用户信息】接口获取用户的openid和access_token

      getopenidandaccesstoken();

 

     }

     catch (exception ex)

     {

      //response.write(ex.tostring());

      //throw;

     }

    }

    return view();

   }

 这里面就是为了获取用户的openid和access_token,这个用途很大,还有就是,我们通过代码可以知道,我们通过这个方法,可以获取到微信的一些相关信息,获取完了之后,他会返回到我们的页面上来,url就存在一个session里面,如下:

 session["url"] = url;       

接着,在前端:

当页面加载完毕之后,会执行以下js方法,如下:

 

?

$( function () {

   var vcode = getquerystring( "code" );

   if (vcode != "" && vcode != null ) {

    //alert(vcode);

    $.ajax({

     type: 'post' ,

     data: {

      code: vcode

     },

     url: '/home/getwxinfo' ,

     success: function (sjson) {

      //alert(sjson);

      //var vdata = json.stringify(sjson);

      //alert(vdata);

      $.messager.show({

       title: '提示' ,

       msg: '欢迎您来到微信端充值中心。'

      });

     }

    })

   }

   else {

    $.ajax({

     type: 'post' ,

     url: '/home/getcode' ,

     success: function (sjson) {

      //alert(sjson);

      location.href = sjson;

     }

    })

   }

  })

他会先获取浏览器的url,然后获取code,就是一般url后面的xxx.com?code=xxx,这里面就是首先判断有无code,如果没有code,则,我们去后台请求这个code。为什么请求这个code呢?我们来看这个方法: getwxinfo,如下图:

?

/// <summary>

   /// 获取code

   /// </summary>

   /// <returns></returns>

   [httppost]

   public actionresult getcode()

   {

    object objresult = "" ;

    if (session[ "url" ] != null )

    {

     objresult = session[ "url" ].tostring();

    }

    else

    {

     objresult = "url为空。" ;

    }

    return json(objresult);

   }

他就会返回url到前端,前端通过js去访问那个网址,那个网址就是微信端获取到我们的信息之后,给我们按照规则再返回一个url,这rul就是我们后面需要后去的code的url。这个code对我们至关重要,因为后面我们要做跟支付有关的工作,都用到的。有了code,我们才能拿到openid和access_token。具体看代码逻辑也可以明了。

好,走到这一步,我们已经知道openid和access_token了,这个时候,我们就负责处理前端的东西。

前端,我就一个金额输入框,然后一个提交,实际应用中,我们肯定还需要传入商品的参数,我这里面就不写那些多余的了,后续你们自己加进去就可以了。这里面在点击提交的时候,会调用微信的环境,看下面的代码:

?

//初始化微信支付环境

  function fcharge() {

   if ( typeof weixinjsbridge == "undefined" ) {

    if (document.addeventlistener) {

     document.addeventlistener( 'weixinjsbridgeready' , onbridgeready, false );

    } else if (document.attachevent) {

     document.attachevent( 'weixinjsbridgeready' , onbridgeready);

     document.attachevent( 'onweixinjsbridgeready' , onbridgeready);

    }

   } else {

    fpostcharge();

   }

  }

他会初始化一下环境,如果初始化成功,代表,这个页面是在微信客户端里面运行的,那么我们就给他运行我们真正的充值代码提交,所以,就会执行:fpostcharge();

提交之后,就会进入后台,后台需要组织我们前台需要用到的参数,其中包括如下:

?

/// <summary>

   /// 充值

   /// </summary>

   /// <returns></returns>

   [httppost]

   public actionresult meterrecharge()

   {

    object objresult = "" ;

    string strtotal_fee = request.form[ "totalfee" ];

    string strfee = ( double .parse(strtotal_fee) * 100).tostring();

 

    //若传递了相关参数,则调统一下单接口,获得后续相关接口的入口参数

    jsapipay.openid = session[ "openid" ].tostring();

    jsapipay.total_fee = int .parse(strfee);

 

    //jsapi支付预处理

    try

    {

     string strbody = "南宫萧尘微信支付" ; //商品描述

     wxpaydata unifiedorderresult = jsapipay.getunifiedorderresult(strbody);

     wxpaydata wxjsapiparam = jsapipay.getjsapiparameters(); //获取h5调起js api参数

 

     modelfororder aorder = new modelfororder()

     {

      appid = wxjsapiparam.getvalue( "appid" ).tostring(),

      noncestr = wxjsapiparam.getvalue( "noncestr" ).tostring(),

      packagevalue = wxjsapiparam.getvalue( "package" ).tostring(),

      paysign = wxjsapiparam.getvalue( "paysign" ).tostring(),

      timestamp = wxjsapiparam.getvalue( "timestamp" ).tostring(),

      msg = "成功下单,正在接入微信支付."

     };

     objresult = aorder;

    }

    catch (exception ex)

    {

     modelfororder aorder = new modelfororder()

     {

      appid = "" ,

      noncestr = "" ,

      packagevalue = "" ,

      paysign = "" ,

      timestamp = "" ,

      msg = "下单失败,请重试,多次失败,请联系管理员."

     };

     objresult = aorder;

    }

    return json(objresult);

   }

我们主要需要提供的就是这个类modelfororder 里面的参数,然后再把这些参数返回给前台调用,如下:

?

//调用微信支付模块

  function onbridgeready(json) {

   weixinjsbridge.invoke(

   'getbrandwcpayrequest' , {

    "appid" : json.appid,  //公众号名称,由商户传入

    "timestamp" : json.timestamp,   //时间戳,自1970年以来的秒数

    "noncestr" : json.noncestr, //随机串

    "package" : json.packagevalue,

    "signtype" : "md5" ,   //微信签名方式:

    "paysign" : json.paysign //微信签名

   },

   function (res) {

    if (res.err_msg == "get_brand_wcpay_request:ok" ) {

     //alert("支付成功,请稍后查询余额,如有疑问,请联系管理员.");

     falreadypay();

    }  // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。

   }

   );

  }

这样,他就会弹出一个微信支付的窗口,如下:

 

然后我们确认付款之后,是否付款成功,如果付款成功,我们在执行: falreadypay();

这个方法已经被我删掉了,用途是用于,我们收到用户的款之后,我们需要同步一些数据到我们的数据库里面去,所以,该怎么操作,自己自行修改了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:http://www.cnblogs.com/nangong/p/50ab3c60f0d1ae5b551373cf96cd060d.html

dy("nrwz");

查看更多关于C# MVC 微信支付教程系列之公众号支付代码的详细内容...

  阅读:40次