• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

.Net后台实现微信小程序支付 - 那么远这么近

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

.Net后台实现微信小程序支付

最近一直再研究微信支付和支付宝支付,官方支付文档中一直在讲与第三方支付打交道的原理,却没有介绍我们自己项目中的APP与后台该怎么交互(哈哈,人家也没必要介绍这一块)。拜读了官方文档和前辈们的佳作,自己在这里做一些总结。

不管是微信支付还是支付宝支付,使用的是小程序、APP或网页都可以用以下示例图来说明。

支付流程:


  ① 支付端将订单号(小程序中还需要传递登录凭证)传递至后台商户。

  ②后台验证订单、统计订单总价,请求第三方获取下单参数。

  ③第三方返回下单参数。

  ④后台将从第三方返回的参数按需要返回至支付端。

  ⑤支付端拿着后台返回的参数下单。

  ⑥第三方返回支付结果。

  ⑦支付成功后,第三方发起支付回调通知商户后台,在这一步,商户可在回调中修改订单以及用户的相关支付状态。

微信小程序支付:


 先放一张官方的图

具体实现:

新建App.Pay项目,在新项目中新建Log类,记录操作过程中的日志。

 1 using System;
 2 using System.Collections.Generic;
 3 using System.IO;
 4 using System.Linq;
 5 using System.Text;
 6 using System.Threading.Tasks;
 7 using System.Web;
 8 
 9 namespace App.Pay
10 {
11     public class Log
12     {
13         //在网站根目录下创建日志目录
14         public string path;
15 
16         public Log(string path)
17         {
18             this.path = HttpContext.Current.Request.PhysicalApplicationPath + path;
19         }
20         /**
21          * 向日志文件写入调试信息
22          * @param className 类名
23          * @param content 写入内容
24          */
25         public void Debug(string className, string content)
26         {
27             WriteLog("DEBUG", className, content);
28         }
29 
30         /**
31         * 向日志文件写入运行时信息
32         * @param className 类名
33         * @param content 写入内容
34         */
35         public void Info(string className, string content)
36         {
37             WriteLog("INFO", className, content);
38         }
39 
40         /**
41         * 向日志文件写入出错信息
42         * @param className 类名
43         * @param content 写入内容
44         */
45         public void Error(string className, string content)
46         {
47             WriteLog("ERROR", className, content);
48         }
49 
50         /**
51         * 实际的写日志操作
52         * @param type 日志记录类型
53         * @param className 类名
54         * @param content 写入内容
55         */
56         protected void WriteLog(string type, string className, string content)
57         {
58             if (!Directory.Exists(path))//如果日志目录不存在就创建
59             {
60                 Directory.CreateDirectory(path);
61             }
62 
63             string time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");//获取当前系统时间
64             string filename = path + "/" + DateTime.Now.ToString("yyyy-MM-dd") + ".log";//用日期对日志文件命名
65 
66             //创建或打开日志文件,向日志文件末尾追加记录
67             StreamWriter mySw = File.AppendText(filename);
68 
69             //向日志文件写入内容
70             string write_content = time + " " + type + " " + className + ": " + content;
71             mySw.WriteLine(write_content);
72 
73             //关闭日志文件
74             mySw.Close();
75         }
76     }
77 }
View Code

新建WePay文件夹,新建Config基类,存放微信支付的公共配置参数。

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 
 7 namespace App.Pay.WePay
 8 {
 9     /**
10     *     配置账号信息
11     */
12     public class WePayConfig
13     {
14         //=======【商户系统后台机器IP】===================================== 
15         /* 此参数可手动配置也可在程序中自动获取
16         */
17         public const string IP = "8.8.8.8";
18 
19 
20         //=======【代理服务器设置】===================================
21         /* 默认IP和端口号分别为0.0.0.0和0,此时不开启代理(如有需要才设置)
22         */
23         public const string PROXY_URL = "";
24 
25         //=======【上报信息配置】===================================
26         /* 测速上报等级,0.关闭上报; 1.仅错误时上报; 2.全量上报
27         */
28         public const int REPORT_LEVENL = 1;
29 
30         //=======【日志级别】===================================
31         /* 日志等级,0.不输出日志;1.只输出错误信息; 2.输出错误和正常信息; 3.输出错误信息、正常信息和调试信息
32         */
33         public const int LOG_LEVENL = 3;
34     }
35 }
View Code

新建Exception类,捕获微信支付过程中的异常。

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 
 7 namespace App.Pay.WePay
 8 {
 9     public class WePayException : Exception
10     {
11         public WePayException(string msg) : base(msg)
12         {
13 
14         }
15     }
16 }
View Code

新建SafeXMLDocument类

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 using System.Xml;
 7 
 8 namespace App.Pay.WePay
 9 {
10     public class SafeXmlDocument : XmlDocument
11     {
12         public SafeXmlDocument()
13         {
14             this.XmlResolver = null;
15         }
16     }
17 }
View Code

新建WeHelper类,目前只有一个方法,微信小程序支付中将登录凭证转换为openId。

 1 using App.Common.Extension;
 2 using Newtonsoft.Json.Linq;
 3 using System;
 4 using System.Collections.Generic;
 5 using System.Configuration;
 6 using System.Linq;
 7 using System.Net;
 8 using System.Security.Cryptography;
 9 using System.Text;
10 using System.Threading.Tasks;
11 
12 namespace App.Pay.WePay
13 {
14     public class WeHelper
15     {
16         // 小程序
17         private static string _appid = ConfigurationManager.AppSettings["wxAPPID"];
18         // 小程序
19         private static string _appSecret = ConfigurationManager.AppSettings["wxAppSecret"];
20 
21         public static WxSession Code2Session(string code)
22         {
23             var url = $"https://api.weixin.qq.com/sns/jscode2session?appid={_appid}&secret={_appSecret}&js_code={code}&grant_type=authorization_code";
24             try
25             {
26                 var request = WebRequest.Create(url);
27                 using (var response = request.GetResponse())
28                 {
29                     using (var rs = response.GetResponseStream())
30                     {
31                         using (var s = new System.IO.StreamReader(rs))
32                         {
33                             return s.ReadToEnd().JsonTo<WxSession>();
34                         }
35                     }
36                 }
37             }
38             catch (Exception)
39             {
40                 return null;
41             }
42         }
43     }
44 
45     public class WxSession
46     {
47         public string openid { get; set; }
48         public string session_key { get; set; }
49         public string errcode { get; set; }
50         public string errMsg { get; set; }
51         public string unionid { get; set; }
52     }
53 
54 }
View Code

以上四个类是微信支付通用的,因此统一放在了微信支付文件夹下。

新建XcxPay文件夹,用于存放微信小程序支付的文件,新建XcxPayConfig类,存放关于小程序支付参数,小程序APPID、账号Secert、商户号、商户支付密钥、支付回调地址。我把这些参数值都放在了解决方案的config配置文件中。

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 using System.Web.Configuration;
 7 
 8 namespace App.Pay.WePay.XcxPay
 9 {
10     public class XcxPayConfig : WePayConfig
11     {
12         //=======【基本信息设置】=====================================
13         /* 微信公众号信息配置
14         * APPID:绑定支付的APPID(必须配置)
15         * MCHID:商户号(必须配置)
16         * KEY:商户支付密钥,参考开户邮件设置(必须配置)
17         * APPSECRET:公众帐号secert(仅JSAPI支付的时候需要配置)
18         */
19         /// 小程序支付
20         public static string APPID = WebConfigurationManager.AppSettings["XcxAppID"].ToString();
21         public static string MCHID = WebConfigurationManager.AppSettings["XcxMchID"].ToString();
22         public static string KEY = WebConfigurationManager.AppSettings["XcxKey"].ToString();
23         public static string APPSECRET = WebConfigurationManager.AppSettings["XcxAppSecret"].ToString();
24 
25         //=======【证书路径设置】===================================== 
26         /* 证书路径,注意应该填写绝对路径(仅退款、撤销订单时需要)
27         */
28         public const string SSLCERT_PATH = "cert/apiclient_cert.p12";
29         public const string SSLCERT_PASSWORD = "1233410002";
30 
31         //=======【支付结果通知url】===================================== 
32         /* 支付结果通知回调url,用于商户接收支付结果
33         */
34         public static string NOTIFY_URL = WebConfigurationManager.AppSettings["XcxNotifyUrl"].ToString();
35 
36         // log记录
37         public static string LogPath = WebConfigurationManager.AppSettings["XcxLog"].ToString();
38     }
39 }
View Code
<!--小程序支付-->
    <add key="XcxAppID" value="" />
    <add key="XcxAppSecret" value="" />
    <add key="XcxMchID" value="" />
    <add key="XcxKey" value="" />
<!--回调通知-->
    <add key="XcxNotifyUrl" value="" />
View Code

新建WeXcxPayApi类

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 using System.Threading.Tasks;
  6 
  7 namespace App.Pay.WePay.XcxPay
  8 {
  9     public class XcxPayApi
 10     {
 11         public static Log Log = new Log(XcxPayConfig.LogPath);
 12 
 13         /**
 14         * 提交被扫支付API
 15         * 收银员使用扫码设备读取微信用户刷卡授权码以后,二维码或条码信息传送至商户收银台,
 16         * 由商户收银台或者商户后台调用该接口发起支付。
 17         * @param WxPayData inputObj 提交给被扫支付API的参数
 18         * @param int timeOut 超时时间
 19         * @throws WePayException
 20         * @return 成功时返回调用结果,其他抛异常
 21         */
 22         public static XcxPayData Micropay(XcxPayData inputObj, int timeOut = 10)
 23         {
 24             string url = "https://api.mch.weixin.qq.com/pay/micropay";
 25             //检测必填参数
 26             if (!inputObj.IsSet("body"))
 27             {
 28                 throw new WePayException("提交被扫支付API接口中,缺少必填参数body!");
 29             }
 30             else if (!inputObj.IsSet("out_trade_no"))
 31             {
 32                 throw new WePayException("提交被扫支付API接口中,缺少必填参数out_trade_no!");
 33             }
 34             else if (!inputObj.IsSet("total_fee"))
 35             {
 36                 throw new WePayException("提交被扫支付API接口中,缺少必填参数total_fee!");
 37             }
 38             else if (!inputObj.IsSet("auth_code"))
 39             {
 40                 throw new WePayException("提交被扫支付API接口中,缺少必填参数auth_code!");
 41             }
 42 
 43             inputObj.SetValue("spbill_create_ip", WePayConfig.IP);//终端ip
 44             inputObj.SetValue("appid", XcxPayConfig.APPID);//公众账号ID
 45             inputObj.SetValue("mch_id", XcxPayConfig.MCHID);//商户号
 46             inputObj.SetValue("nonce_str", Guid.NewGuid().ToString().Replace("-", ""));//随机字符串
 47             inputObj.SetValue("sign", inputObj.MakeSign());//签名
 48             string xml = inputObj.ToXml();
 49 
 50             var start = DateTime.Now;//请求开始时间
 51 
 52             Log.Info("XcxPayApi", "MicroPay request : " + xml);
 53             string response = XcxPayHttpService.Post(xml, url, false, timeOut);//调用HTTP通信接口以提交数据到API
 54             Log.Info("XcxPayApi", "MicroPay response : " + response);
 55 
 56             var end = DateTime.Now;
 57             int timeCost = (int)((end - start).TotalMilliseconds);//获得接口耗时
 58 
 59             //将xml格式的结果转换为对象以返回
 60             XcxPayData result = new XcxPayData();
 61             result.FromXml(response);
 62 
 63             ReportCostTime(url, timeCost, result);//测速上报
 64 
 65             return result;
 66         }
 67 
 68 
 69         /**
 70         *    
 71         * 查询订单
 72         * @param WxPayData inputObj 提交给查询订单API的参数
 73         * @param int timeOut 超时时间
 74         * @throws WePayException
 75         * @return 成功时返回订单查询结果,其他抛异常
 76         */
 77         public static XcxPayData OrderQuery(XcxPayData inputObj, int timeOut = 6)
 78         {
 79             string url = "https://api.mch.weixin.qq.com/pay/orderquery";
 80             //检测必填参数
 81             if (!inputObj.IsSet("out_trade_no") && !inputObj.IsSet("transaction_id"))
 82             {
 83                 throw new WePayException("订单查询接口中,out_trade_no、transaction_id至少填一个!");
 84             }
 85 
 86             inputObj.SetValue("appid", XcxPayConfig.APPID);
                      

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap