[微信支付]C# .net 微信扫码Native支付模式二以及成功回调

0x0001 前言

经过一周的摧残,终于完成了微信支付,做完总结一下,觉得其实并不难,主要是网上没有一个明确的教程.
本文是基于C#语言上进行开发,其实本人是做java的,但由于最近接手维护的项目是C#的,所以也强制让自己简单的熟悉一遍C#(偷偷的说,我C# .net .asp都还没清楚,不过最重要的是思路,语言只是一种工具~~~)

0x0002 项目背景(可略过)

  1. 项目类型:在线考试系统;
  2. 项目要求:让之前全部免费的试卷部分收费,故选用微信支付 (PS:早知道微信支付官方文档这么坑,就选型支付宝了)
  3. 项目业务:系统暂时要求点击支付时网站弹出生成的微信支付二维码,由用户进行扫描购买,购买完成后用户可使用已购买的商品(试卷);
  4. 微信支付产品选型:微信有多种支付模式,如下:
    在这里插入图片描述
    根据实际情况需求,推荐使用Native支付,此种方式简单也能完成我们的需求.(一开始选的JSAPI,但是后来实在做不动了,就换了Native支付,不过现在看来,都差不多,只是JSAPI需要多获取几个微信指定的属性)

Native支付是指商户系统按微信支付协议生成支付二维码,用户再用微信“扫一扫”完成支付的模式。该模式适用于PC网站、实体店单品或订单、媒体广告支付等场景。

0x0003 开发思路

  • 简单来说:微信扫码支付就是我们把需要的信息生成二维码,然后用户扫描二维码就出现了我们想要展示的信息.
  • 稍复杂来说:微信扫码支付就是我们把部分重要信息(商品价格\商品id等)发送给微信服务端,微信返回生成包含我们提交数据且加密的微信支付协议的URL,我们接收此URL并将其生成一个二维码图片,用户通过微信扫一扫,发起支付。
  • 总体来说:
    1.注册微信商户号,接入微信支付,配置微信支付平台的 支付授权目录扫码回调链接;
    2.用户点击支付时,前端向服务端传递相关数据id;
    3.服务端接收id后查询核对,按照微信扫码支付规则调用微信支付接口;
    4.微信支付接口根据一系列数据比如(商品价格\商品id)加密生成签名后返回一个带微信支付协议的URL;
    5.使用相关生成二维码的工具(QRCode.js)将URL生成二维码图片;
    6.用户扫码跳到支付界面,点击支付后,微信服务端调用我们的扫码回调链接;
    7.需要提前写好扫码回调链接的类或方法,根据微信传来的诗句在此核对数据,通过则更改自己系统的某状态,并返给微信服务端成功.

0x0004 开发过程

0.准备工作

  • 申请 微信商户号 微信公众号 (这里具体步骤不描述,因为这属于公司申请):
  • 开通 Native支付(点击开通,很简单,但需要管理员账号)
  • 安装 微信认证证书

1.下载官方工具类(Native 模式二)

官方文档地址:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_5
先下载官方提供的工具类Demo
https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=11_1
在这里插入图片描述

2.解压并进入WxPayAPI文件夹,将 business example lib 三个文件夹复制到咱们项目的工程中(本项目使用VS ,如果不会添加 ,VS将复制过来的文件或文件夹显示到解决方案管理)

在这里插入图片描述
在这里插入图片描述

3.虽然是三个文件夹,但对于我们Native开发模式二,仅需改3个文件,也就是每个文件夹下一个,就可以完美运行]

(1)business文件夹 NativePay.cs 推荐其他文件不删除

在这里插入图片描述

(2)example文件夹 ResultNotifyPage.aspx,推荐删除其他文件,并将此文件放在工程根目录下

在这里插入图片描述
如:
在这里插入图片描述

(3)lib文件夹全部保留,因为这里面是所依赖的工具类。

4.后端进行页面配置

(1)对于lib文件夹,仅需修改DemoConfig.cs[作用:配置微信商户号和公众号、回调地址等相关信息];

在这里插入图片描述
对于这个页面,我们仅需要修改4个地方:

在这里插入图片描述
在这里插入图片描述
将内容写在 return 后面的引号里

以下是这4个的介绍
①Appid:绑定支付的APPID(必须配置) 登录微信公众号可以查到 (商户号必须绑定一个公众号才可以,这个APPID是微信公众号的);
在这里插入图片描述
②Mchid:商户号(必须配置) 登录 微信商户平台 可以查到在这里插入图片描述
③ Key:商户支付密钥,参考开户邮件设置(必须配置),请妥善保管,避免密钥泄露 ;
在这里插入图片描述
④NotifyUrl: 支付结果通知回调url,用于商户接收支付结果
在这里插入图片描述

注:a.这个链接必须外网,如需内网开发测试可参考微信支付-使用Natapp实现本地内网进行开发测试以及解决webpack "Invalid Host header"问题
\b.ResultNotifyPage.aspx为刚才 **3(2)**中所保留的那个文件

(2)对于business文件夹,仅需修改NativePay.cs文件[作用:用来调用微信接口根据我们提供的数据生成二维码链接]

下拉代码找到模式二,仅需修改模式二的代码
在这里插入图片描述
①可修改方法参数列表 product_id不要动,其他的可随意修改,传递值时,将主键传到product_id中
②可修改data.SetValue(键,值)的值

键可参考 官方文档:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1
我这里只给出上面图片显示的键对应的内容:
在这里插入图片描述

注1:body商品描述 是用户在扫码后显示的标题,如下

在这里插入图片描述
微信支付-C# .net 微信扫码支付Body含有中文导致出现“签名错误”

注2:total_fee商品金额 单位是分!!!单位是分!!!单位是分!!!推荐传值或在当前页面直接根据商品id直接查金额,防止被篡改;
注3:trade_type交易类型 一定为NATIVE. product_id商品ID不要改,接收传递的ID即可;
注4:其他属性可保持原来的或自己添加 .

(2)对于ResultNotifyPage.aspx文件,仅需修改ResultNotifyPage.aspx.cs文件[作用:用户支付成功后,微信服务端发送信息到这个页面提醒我们核对信息并更新状态]

原版代码为:
在这里插入图片描述
我们要获取微信服务端返回来的数据使用上述代码的这个方法 resultNotify.ProcessNotify();
此方法有返回值,原版代码没写,在这里我们需要写上返回值.

WxPayData notifyData = resultNotify.ProcessNotify();

然后开始写逻辑:关于我系统的代码如下:

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Text;
using TeachAssis.Model;

namespace WxPayAPI
{
    public partial class ResultNotifyPage : System.Web.UI.Page
    {
        private TeachAssis.Service.OrderService orderService = new TeachAssis.Service.OrderService();//项目所用的业务逻辑层
        private TeachAssis.Service.StuExamService stuExamService = new TeachAssis.Service.StuExamService();//项目所用的业务逻辑层
        protected void Page_Load(object sender, EventArgs e)
        {
            ResultNotify resultNotify = new ResultNotify(this);
            WxPayData notifyData = resultNotify.ProcessNotify();//添加上返回值;
            if (notifyData != null)//判断微信传递的数据是否为空,不为空则可以进入
            {
                //支付回调,微信连续发送8次请求,result_code此字段是通信标识,非交易标识,交易是否成功需要查看result_code来判断,可参考 https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1
                if (notifyData.IsSet("result_code"))//成功返回 SUCCESS 则进入判断
                {
                    //1.通过传递的订单号先查询是否存在此订单,如果订单存在则进行下一步 这一步已经在 resultNotify.ProcessNotify()方法中自行完成
                    //2.核对系统订单金额与微信订单中金额是否一致
                    //2.1 先通过传递的考试订单id从订单表查询订单金额
                    String order_id=(String)notifyData.GetValue("attach");
                    Orders ord = orderService.GetModel(order_id);
                    if (ord!=null) {
                        //2.2 将查出的金额单位由元变为分
                        int money = (int)(ord.ExamMoney * 100);
                        //2.3 与微信订单中金额进行对比,不一致,返回非法操作
                        int WXMoney = Convert.ToInt32(notifyData.GetValue("total_fee"));
                        if (money == WXMoney)
                        {
                            //签名
                            String sign = ((String)notifyData.GetValue("sign")).ToUpper();
                            if (sign!=null&&!"".Equals(sign))
                            {
                                ord.Test3 = sign;
                                //3.核对其他信息是否正确
                                String sign2 = notifyData.MakeSign().ToUpper();

                                if (sign.Equals(sign2))
                                {
                                    //将结束时间存到当前订单中
                                    String time_end = (String)notifyData.GetValue("time_end");
                                    ord.EndTime = time_end;
                                    //将微信给商户生成的订单号存在当前订单中Test1 
                                    String out_trade_no = (String)notifyData.GetValue("out_trade_no");
                                    ord.Test1 = out_trade_no;
                                    //将微信订单号存在当前订单中PayID 
                                    String transaction_id = (String)notifyData.GetValue("transaction_id");
                                    ord.PayID = transaction_id;
                                    //将微信用户用户标识(用户在商户appid下的唯一标识)存在当前订单中Test2
                                    String openid = (String)notifyData.GetValue("openid");
                                    ord.Test2 = openid;
                                    //将是否关注公众账号存在当前订单中Test3(用户是否关注公众账号,Y-关注,N-未关注)
                                    String is_subscribe = (String)notifyData.GetValue("is_subscribe");
                                    ord.Test3 = is_subscribe;
                                    //在Orders表中修改订单的状态为2,已支付
                                    ord.PayStatus = 2;
                                    b = orderService.Save(ord);
                                    //在StuExam表中新建一条记录
                                    StuExam stuExam = new StuExam { StuID = ord.StuID, CreatTime = DateTime.Now, ExamID = ord.ExamID, Status = 1 };
                                    if (stuExamService.IsExsit(ord.StuID, ord.ExamID)) {
                                        //如果存在记录,则只需要更改状态
                                        String[] strPK = { ord.StuID, ord.ExamID };
                                        StuExam stu = stuExamService.GetModel(strPK);
                                        stu.Status = 1;
                                        stuExamService.Save(stu);
                                    }
                                    else {
                                        //如果不存在记录
                                        stuExamService.Add(stuExam);
                                    }
                                }
                            }                           
                        }
                        else
                        {
                            //暂无操作
                        }
                    }
                    
                }
            }
        }       
    }
}

其实代码很简单,就是将 notifyData里的数据,通过 notifyData.GetValue("XXXX")方法获取出来,然后和订单中比一下,再调用微信生成签名的工具重新生成签名对比一下,保证安全性,如果通过,则修改订单状态即可.

到这里所有后台需要修改的微信代码全部完成,还缺一个接收通过微信接口生成的微信支付协议的链接,通过这个链接我们在前台转换成二维码即可.

5.前端进行页面配置

本系统前端使用vue,生成二维码的工具为QRCode.js
QRCode在一般项目中引入可参考 http://www.runoob.com/w3cnote/javascript-qrcodejs-library.html
在vue中
0.在项目文件夹中的打开cmd命令窗口输入npm install qrcodejs2 --save 安装qrcode
1.在使用的界面导入 import QRCode from 'qrcodejs2' 使用qrcode
2.在使用的位置放入div <div id="qrcode"></div> //生成二维码的位置
3.在js中(vue项目中) methods:{} 中写以下方法,先获取元素节点,然后将节点内容清空,使用new QRCode(qr,Xxx);
Xxx是微信接口返给我们的URL地址
在这里插入图片描述
4.调用此方法:我的调用流程为,点击报名(在点击事件中将想要购买的商品id通过路由传到微信支付接口)
在这里插入图片描述
,然后弹出模态窗口(微信支付接口生成url链接,QRCode根据url生成图片展示在页面上),
在这里插入图片描述
附部分代码和逻辑:(这里其实可以很简单的写,看自己的习惯)
在这里插入图片描述
这里使用了延时加载,因为有时候页面刷新太快,导致加载跟不上.

到这里就写完了,虽然内容很多,总结一下很少
1.下载微信demo,将那三个文件夹加入工程
2.修改那3个文件
3.前端向微信接口传值,返回URL
4.QRCode根据URL生成二维码

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章