C# MVC 微信支付教程系列之公众号支付代码
今天,我们接着讲微信支付的系列教程,前面,我们讲了这个微信红包和扫码支付。现在,我们讲讲这个公众号支付。公众号支付的应用环境常见的用户通过公众号,然后再通过公众号里面的菜单链接,进入公众号的商城,然后在里面完成购买和支付功能,我们可以看看官方对这个公众号支付的场景的解释,链接:,通过这个官方的解释,那我们大概清楚这个公众号的用途了,下面,我就说说,做这个公众号支付的准备工作有哪些了。
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的,可以下载来参考:),名为:微信支付之公众号支付,如下图:
然后右键项目,我们修改一下属性,如下图:
然后我们再把程序自动生成的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发布在上 ,然后再把接口权限,改为这样的,如下图:
注意,这里面的域名和上面我们发布的域名要一致。
除此以外,我们还需要改这里:
就是一定要授权这里,否则,支付的时候,会提示其他错误,具体,我就不测试了。
另外,这里其实已经完成了这个公众号的支付的流程了,但是,我们页面上,会友善的提醒(其实不友善,提示是红色的,在头部,提示别输入密码什么),这是因为,我们还没把咱们这个域名设置为安全域名,设置之后,就不会在提示了。设置方法如下图:
在这里面加入咱们的域名,就完美了。。。
我的代码都尽量精简,多余的,我都会丢掉,就是为了避免混淆视听。如果代码里面,有写的不清楚的,可以私信问我,或群里来问我,群号在文章末端。
现在,我开始一一解释我上面的做法。
首先,在后端,页面加载的时候,他会先执行
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();
这个方法已经被我删掉了,用途是用于,我们收到用户的款之后,我们需要同步一些数据到我们的数据库里面去,所以,该怎么操作,自己自行修改了。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。