asp.net core 微信扫码支付(扫码支付,H5支付,公众号支付,app支付)之1
2018-08-13更新生成二维码的方法
在做微信支付前,首先要了解你需要什么方式的微信支付,目前本人做过的支付包含扫码支付、H5支付、公众号支付、App支付等,本人使用的是asp.net mvc core2.0框架开发,core技术目前国内用的不算多,所以本人总结使用asp.net mvc core开发微信支付的一些经验,之前都在博客园学习,没有写过文章,文笔差,欢迎指正。
首先定义个微信支付参数保存的类,本人定义类如下,具体参数意义就只有去参考微信官方文档了,后台接口开发都将用到这边的参数,若支付不使用公众号支付和app支付的话appSecret参数将不用获取。
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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
扫码支付服务类方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | /// <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 "" ; } } |
后台控制器中代码参考
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | /// <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引用,代码例如
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 该段代码无效[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标签正确显示了扫码的图片,那么就大功告成了,支付完成,但是还有支付回调更新订单的逻辑要写。
效果如下:
这里再贴上微信支付回调的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | /// <summary> /// 微信支付异步回调 /// </summary> /// <returns></returns> public IActionResult WxNotify() { try { //使用微信工具获取ResponseHandler ResponseHandler wxResponseHandler = new ResponseHandler(HttpContext);<br> 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(); //后面去可以去配置或者数据库中获取<br> //验证是否通过微信安全认证 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请求方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /// <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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具