zoukankan      html  css  js  c++  java
  • asp.net core 微信扫码支付(扫码支付,H5支付,公众号支付,app支付)之1

      2018-08-13更新生成二维码的方法

      在做微信支付前,首先要了解你需要什么方式的微信支付,目前本人做过的支付包含扫码支付、H5支付、公众号支付、App支付等,本人使用的是asp.net mvc core2.0框架开发,core技术目前国内用的不算多,所以本人总结使用asp.net mvc core开发微信支付的一些经验,之前都在博客园学习,没有写过文章,文笔差,欢迎指正。

      首先定义个微信支付参数保存的类,本人定义类如下,具体参数意义就只有去参考微信官方文档了,后台接口开发都将用到这边的参数,若支付不使用公众号支付和app支付的话appSecret参数将不用获取。

    public class WxPayConfig
        {
            public static WxPayConfig Instance = new WxPayConfig();
    
            public string appid = "";//APPID
    
            public string mchid = "";//商户号
    
            public string key = "";//商户API密钥
    
            public string appSecret = "";//公众号支付和app支付时候将用到
    
            public string notify_url = "http://www.baidu.com/Pay/WxNotify";//回调页地址
    
            public string api_url = "https://api.mch.weixin.qq.com/pay/unifiedorder";//微信支付调用接口地址
        }
    

      首先说一下扫码支付大体流程,首先微信得开通商户平台得扫码支付功能具体在 https://pay.weixin.qq.com上登陆,填写相关才材料开通扫码支付,开通完成后支付产品里将出现已开通的支付列表,然后使用获取到的参数拼接成对应格式的xml文件上传到微信服务器,如果配置正常服务器将返回一串xml文本,获取xml文本中的code_url地址,将该地址转为图片二维码展示在网站中。

    1.申请扫码支付接口


    2.配置微信扫码支付回调链接(貌似不配置扫码支付也可以用)


    3.编写扫码支付服务, 扫码支付需要用到的appid,mchid,key 等参数,代码如下


    首先在nuget中安装Senparc.Weixin.MP

    扫码支付服务类方法:

    /// <summary>
            /// 获取微信扫码支付URL
            /// </summary>
            /// <param name="out_trade_no">订单号</param>
            /// <param name="body">描述</param>
            /// <param name="total_fee">总价</param>
            /// <param name="ip">客户IP</param>
            /// <param name="product_id">商品id</param>
            /// <returns></returns>
            public string GetWxSMPayUrl(string out_trade_no, string body, string total_fee, string ip, string product_id)
            {
                Senparc.Weixin.MP.TenPayLibV3.RequestHandler packageReqHandler = new Senparc.Weixin.MP.TenPayLibV3.RequestHandler();
                #region 构造请求参数
                packageReqHandler.SetParameter("appid", wxPayConfig.appid);//APPID
                packageReqHandler.SetParameter("mch_id", wxPayConfig.mchid);//商户号
                packageReqHandler.SetParameter("nonce_str", Senparc.Weixin.MP.TenPayLibV3.TenPayV3Util.GetNoncestr());//随机串
                packageReqHandler.SetParameter("body", body);
                packageReqHandler.SetParameter("out_trade_no", out_trade_no);//订单号
                packageReqHandler.SetParameter("total_fee", (int)(Convert.ToDecimal(total_fee) * 100) + ""); //金额,以分为单位
                packageReqHandler.SetParameter("spbill_create_ip", ip);//IP
                packageReqHandler.SetParameter("notify_url", wxPayConfig.notify_url); //回调地址
                packageReqHandler.SetParameter("trade_type", "NATIVE");//扫码支付
                packageReqHandler.SetParameter("product_id", product_id);//商品ID
                packageReqHandler.SetParameter("sign", packageReqHandler.CreateMd5Sign("key", wxPayConfig.key));//商户API密钥(签名) 
                #endregion
    
                //将参数转为xml字符串
                string data = packageReqHandler.ParseXML();
                //发起post异步请求,获取返回的内容
                var result = PostWithStringFile(wxPayConfig.api_url, data);
                Log.Info("【GetWxSMPayUrl】订单:" + out_trade_no + ",请求得到的xml:" + result, "微信支付");
    
                //解析xml,获取扫码需要的mweb_url。
                var res = System.Xml.Linq.XDocument.Parse(result);
                try
                {
                    string mweb_url = res.Element("xml").Element("code_url").Value;
                    Log.Info("【GetWxSMPayUrl】订单:" + out_trade_no + ",请求得到的url:" + mweb_url, "微信支付");
                    return mweb_url;
                }
                catch (Exception ex)
                {
                    Log.Info("【GetWxSMPayUrl】订单:" + out_trade_no + ",异常:" + ex.ToString(), "微信支付");
                    return "";
                }
            }
    

      后台控制器中代码参考

    /// <summary>
            /// ajax请求生成订单,插入订单到数据库,
            /// </summary>
            /// <param name="body"></param>
            /// <param name="total_fee"></param>
            /// <param name="product_id"></param>
            /// <returns></returns>
            public IActionResult GetWxSMPayUrl(string body, string total_fee, string product_id)
            {
                string no = DateTime.Now.ToString("yyyyMMddHHmmssfff");//构造订单号
                //订单相关逻辑代码
    
                //订单相关逻辑代码结束
    
                //构造支付地址信息
                WxPayService wxPayService = new WxPayService(); //服务类,自行优化
                //获取请求ip
                var ip = Request.Headers["X-Forwarded-For"].FirstOrDefault();
                if (string.IsNullOrEmpty(ip))
                {
                    ip = HttpContext.Connection.RemoteIpAddress.ToString();
                }
                string code_url = wxPayService.GetWxSMPayUrl(no, body, total_fee, ip, product_id);
                return Content(code_url); //返回支付的Url,前端ajax请求得到该url后,将该url赋值到存放图片的src中
    
    
            }
    

      如果业务正常运行ajax将请求得到一串url,后台控制器中添加一个可以根据参数生成二维码图片文件的action,首先在nuget中添加QRCode引用,代码例如

    该段代码无效
    [HttpGet] /// <summary> /// 生成二维码,生成微信扫码支付二维码 /// </summary> /// <param name="data"></param> /// <returns></returns> public FileResult MakeQRCode(string data) { if (string.IsNullOrEmpty(data)) throw new ArgumentException("data"); //初始化二维码生成工具 QRCodeEncoder qrCodeEncoder = new QRCodeEncoder(); qrCodeEncoder.QRCodeEncodeMode = QRCodeEncoder.ENCODE_MODE.BYTE; qrCodeEncoder.QRCodeErrorCorrect = QRCodeEncoder.ERROR_CORRECTION.M; qrCodeEncoder.QRCodeVersion = 0; qrCodeEncoder.QRCodeScale = 4; //将字符串生成二维码图片 Bitmap image = qrCodeEncoder.Encode(data, System.Text.Encoding.Default); //保存为PNG到内存流 MemoryStream ms = new MemoryStream(); image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg); return File(ms.ToArray(), "image/jpeg"); }
    该段代码无效结束
    
    

      以上生成二维码的方法是在.net framework下的,而且缺少一个dll的引用,在core平台下无效,替换为如下而在.net core平台应该使用如下方法:

    在Home控制器中添加MakeQRCode的方法,代码如下:

    public FileResult MakeQRCode(string data)
    {
                var image = QRCoderHelper.CreateQrcode(data);
                MemoryStream ms = new MemoryStream();
                image.Save(ms, System.DrawingCore.Imaging.ImageFormat.Jpeg);
                return File(ms.ToArray(), "image/jpeg");
    }
    QRCoderHelper.cs需要引用NUGET里的ZKWeb.Fork.QRCoder,注:如果之前在NUGET中引用了QRCode请将他移除不然无法使用
    QRCoderHelper

    代码内容如下
    using System;
    using System.DrawingCore;
    using System.DrawingCore.Drawing2D;
    using System.DrawingCore.Imaging;
    using System.IO;
    using QRCoder;
    
    public class QRCoderHelper
        {
            /// <summary>
            /// 生成二维码
            /// </summary>
            /// <returns></returns>
            public static Bitmap CreateQrcode(string codeToken, int version = 10)
            {
                EncoderParameter myEncoderParameter;
                EncoderParameters myEncoderParameters;
                QRCodeGenerator qrGenerator = new QRCodeGenerator();
                // 设置二维码排错率,可选L(7%)、M(15%)、Q(25%)、H(30%),排错率越高可存储的信息越少,但对二维码清晰度的要求越小
                QRCodeData qrCodeData = qrGenerator.CreateQrCode(codeToken, QRCodeGenerator.ECCLevel.Q);
                QRCode qrCode = new QRCode(qrCodeData);
                // 设置设置二维码版本,取值范围1-40,值越大尺寸越大,可存储的信息越大(实测9(297*297),10(330*330),20(660*600),每个挡位33左右,3个挡位100个像素)
                Bitmap qrCodeImage = qrCode.GetGraphic(version);
                Encoder myEncoder = Encoder.Quality;
                myEncoderParameters = new EncoderParameters(1);
                myEncoderParameter = new EncoderParameter(myEncoder, 25L);
                myEncoderParameters.Param[0] = myEncoderParameter;
                return qrCodeImage;
            }
    }
     

      该action作用为请求该方法传入data参数,返回的是该参数值的二维码图片文件,前端src指向该action并加上之前获取得到的code_url信息,格式如下, /Home/MakeQRCode?data=xxxxx,如果img标签正确显示了扫码的图片,那么就大功告成了,支付完成,但是还有支付回调更新订单的逻辑要写。

    效果如下:

      这里再贴上微信支付回调的代码

    /// <summary>
            /// 微信支付异步回调
            /// </summary>
            /// <returns></returns>
            public IActionResult WxNotify()
            {
                try
                {
                    //使用微信工具获取ResponseHandler
                    ResponseHandler wxResponseHandler = new ResponseHandler(HttpContext);
    string out_trade_no = wxResponseHandler.GetParameter("out_trade_no");//订单号 string total_fee = wxResponseHandler.GetParameter("total_fee");//订单金额,单位分 total_fee = (Convert.ToDecimal(total_fee) / 100).ToString("#0.00");//订单金额,单位元 Log.Info("微信测试收到数据,订单号:" + out_trade_no + "订单金额:" + total_fee, "【微信支付回调】"); //验证订单是否有支付过逻辑      //验证订单信息,获取支付配置 WxPayConfig payConfigModel = new WxPayConfig();//后面去可以去配置或者数据库中获取
    //验证是否通过微信安全认证 WxPayService wxPayService = new WxPayService(); bool vxCheck = wxPayService.WxPayCheck(wxResponseHandler);//使用sdk去验证 if (vxCheck) { //更新订单 //ProcessOrder(out_trade_no); Log.Info("微信验证成功" + out_trade_no, "【微信支付回调】"); return SuccessRes(""); } else { Log.Info("微信测试失败" + out_trade_no, "【微信支付回调】"); return ErrRes("微信测试失败"); } } catch (Exception ex) { Log.Error("微信测试回调异常", ex, "【微信支付回调】"); return ErrRes("微信测试回调异常"); } }

      具体业务逻辑实现得看自己的需求,日志类Log和返回成功或者错误信息可自由替换。

    附上方法中用到post请求方法

    /// <summary>
            /// post请求,将字符串转为流上传到url中
            /// </summary>
            /// <param name="url"></param>
            /// <param name="file"></param>
            /// <returns></returns>
            public string PostWithStringFile(string url, string file)
            {
                var formDataBytes = file == null ? new byte[0] : Encoding.UTF8.GetBytes(file);//将xml字符串转为字节流
                MemoryStream ms = new MemoryStream(formDataBytes);//将字节流转为内存流
                StreamContent streamContent = new StreamContent(ms);//封装为StreamContent对象
                //发起post异步请求,获取返回的内容
                var result = httpClient.PostAsync(wxPayConfig.api_url, streamContent).Result.Content.ReadAsStringAsync().Result;
                return result;
            }
    
    //以及服务类包含字段
    #region 字段
            public WxPayConfig wxPayConfig = new WxPayConfig();//微信配置文件
            public HttpClient httpClient = new HttpClient();//http请求客户端
            #endregion
    

      

    附上写日志的一个老师傅写类库Sky.Logger,在项目中添加引用即可使用日志:链接: https://pan.baidu.com/s/1eHdNGZN0pmNHsO_yHzgE_g 密码: ta2x

    欢迎指正。

    QRCoderHelper
  • 相关阅读:
    Redis02——Redis单节点安装
    Redis01——Redis产生背景
    验证元素的唯一性(二重循环法和快排优化)
    线性同余法的伪随机数
    转载(为啥要对10000007取模)
    (算法专题)使用常微分方程将递归转换为非递归
    算法设计与分析——习题一
    PAT Basic 1030 完美数列 (25 分)
    禁止yum update 自动更新系统内核
    Redis AOF 持久化方式
  • 原文地址:https://www.cnblogs.com/jomzhang/p/9199156.html
Copyright © 2011-2022 走看看