【.net core】微信支付基础功能(开发及使用)

目录

注意

正文

微信支付类

HTTP处理类

 二维码生成类

使用方法

微信支付回调示例

下单调用示例

退款示例

订单查询

退款订单查询


注意

微信开发前期准备工作参照:【微信开发】微信支付前期准备工作(申请及配置)-CSDN博客

本文仅提供微信支付下单,付款,回调,退款等基础功能内容,更多微信支付功能请参照微信支付官网:微信支付开发者文档

正文

微信支付类

using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Parameters;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Security.Cryptography;

namespace WaterCloud.Code.Web
{
    /// <summary>
    /// 微信支付类
    /// 微信支付版本:V3
    /// 所有方法只使用了接口提供的部分参数,可更具业务场景需要修改接口参数
    /// </summary>
    public class WXPayHelper
    {


        #region 公共参数
        /// <summary>
        /// 公众平台AppId
        /// 这里填写你自己的公众平台AppId
        /// </summary>
        public static  string appid = "自己的公众平台appid";
        /// <summary>
        /// 商户号
        /// 这里填写你自己的商户号
        /// </summary>
        public static  string mch_id = "自己的商户id";
        /// <summary>
        /// 特约商户微信支付API秘钥
        /// 这里填写你自己的特约商户微信支付API秘钥
        /// </summary>
        public static  string wxPayApiKey = "自己的api密钥";
        /// <summary>
        /// 商户私钥
        /// (微信支付文档->下载并配置商户证书时生成)
        /// NOTE: 私钥不包括私钥文件起始的-----BEGIN PRIVATE KEY-----
        /// 亦不包括结尾的-----END PRIVATE KEY-----
        /// 这里填写你自己的商户私钥
        /// </summary>
        public static  string privateKey = @"自己的私钥";
        /// <summary>
        /// 商户证书序列号
        /// (微信支付文档->下载并配置商户证书时生成)
        /// 这里填写你自己的商户证书序列号
        /// </summary>
        public static  string certificateKey = "自己的序列号";
        /// <summary>
        /// 回调地址
        /// (微信支付后自动回调商户平台的外网地址,微信平台自动调用,用于处理支付后的工作)
        /// 一般用于通过微信调用该接口地址传入的参数解析后获取支付结果,处理不同支付结果的业务逻辑
        /// 需与微信商户号中支付目录地址配置一致
        /// 回调地址随便外网能访问就行  /tPosition/WX_Callback
        /// 注意!!!!!! 不以“/”结尾
        /// </summary>
        public static  string notifyurl = "自己的回调地址";
        /// <summary>
        /// 统一退款接口
        /// 微信支付平台提供的统一退款接口地址
        /// </summary>
        private readonly string OutUrl = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds";
        #endregion

        #region 公共参数类
        #region 下单基类
        /// <summary>
        /// 下单请求参数基类
        /// 详情参见链接:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_1.shtml 请求参数
        /// </summary>
        private class PayOrderbodyModelBase
        {
            /// <summary>
            /// 直连商户号
            /// </summary>
            public string mchid { get; set; }
            /// <summary>
            /// 应用ID
            /// </summary>
            public string appid { get; set; }
            /// <summary>
            /// 商品描述
            /// </summary>
            public string description { get; set; }

            /// <summary>
            /// 商户订单号
            /// </summary>
            public string out_trade_no { get; set; }
            /// <summary>
            /// 通知地址
            /// </summary>
            public string notify_url { get; set; }
            /// <summary>
            /// 订单金额
            /// </summary>
            public object amount { get; set; }


        }

        /// <summary>
        /// 下单返回结果基类
        /// </summary>
        private class ReturnParametersBase
        {
            /// <summary>
            /// 返回结果【true/false】
            /// </summary>
            public bool result { get; set; }
            /// <summary>
            /// 错误描述
            /// </summary>
            public string errmsg { get; set; }
        }

        /// <summary>
        /// 通用订单金额类
        /// 详情参见链接:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_1.shtml
        /// 请求参数中 的 订单金额(amount)参数
        /// </summary>
        private class amount
        {
            /// <summary>
            /// 金钱
            /// </summary>
            public int total { get; set; }
            /// <summary>
            /// 货币类型
            /// CNY:人民币,境内商户号仅支持人民币。
            /// </summary>
            public string currency { get; set; } = "CNY";
        }

        /// <summary>
        /// 通用订单金额类
        /// 详情参见链接:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_1.shtml
        /// 请求参数中 的 场景信息(scene_info)参数
        /// </summary>
        private class scene_info
        {
            /// <summary>
            /// 用户终端IP
            /// 用户的客户端IP,支持IPv4和IPv6两种格式的IP地址。
            /// 示例值:14.23.150.211
            /// </summary>
            public string payer_client_ip { get; set; }
            /// <summary>
            /// H5场景信息
            /// </summary>
            public object h5_info { get; set; }
        }

        /// <summary>
        /// 通用H5场景信息类
        /// 详情参见链接:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_1.shtml
        /// 请求参数中 的 场景信息(scene_info)参数
        /// </summary>
        private class h5_info
        {
            /// <summary>
            /// 场景类型
            /// 示例值:iOS, Android, Wap
            /// </summary>
            public string type { get; set; }
        }
        #endregion
        #region 支付通知结果
        /// <summary>
        /// 统一支付通知结果类
        /// 详情参考:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_5.shtml 通知参数
        /// </summary>
        public class PayResult
        {
            /// <summary>
            /// 通知ID 通知的唯一ID 示例值:EV-2018022511223320873
            /// </summary>
            public string id { get; set; }
            / <summary>
            / 通知ID 通知的唯一ID 示例值:EV-2018022511223320873
            / </summary>
            //public string prepay_id { get; set; }
            /// <summary>
            /// 通知创建时间
            /// 通知创建的时间,遵循rfc3339标准格式,格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE,yyyy-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss.表示时分秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。例如:2015-05-20T13:29:35+08:00表示北京时间2015年05月20日13点29分35秒。
            /// 示例值:2015-05-20T13:29:35+08:00
            /// </summary>
            public string create_time { get; set; }
            /// <summary>
            /// 通知数据类型
            /// </summary>
            public string resource_type { get; set; }
            /// <summary>
            /// 通知类型
            /// </summary>
            public string event_type { get; set; }
            /// <summary>
            /// 回调摘要
            /// </summary>
            public string summary { get; set; }
            /// <summary>
            /// 返回成功的链接
            /// </summary>
            public Resource resource { get; set; }
        }
        /// <summary>
        /// 统一通知数据类
        /// 详情参考:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_5.shtml 
        /// 通知参数 中 通知数据(resource)成员
        /// </summary>
        public class Resource
        {
            /// <summary>
            /// 原始类型
            /// </summary>
            public string original_type { get; set; }
            /// <summary>
            /// 加密算法类型
            /// </summary>
            public string algorithm { get; set; }
            /// <summary>
            /// 数据密文
            /// </summary>
            public string ciphertext { get; set; }
            /// <summary>
            /// 附加数据
            /// </summary>
            public string associated_data { get; set; }
            /// <summary>
            /// 随机串
            /// </summary>
            public string nonce { get; set; }
        }
        #endregion
        #region 订单/支付通知结果报文解析结果
        /// <summary>
        /// 统一通知数据解析结果类
        /// 详情参见:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_2.shtml 返回参数
        /// </summary>
        public class ResourceReslt
        {
            /*微信支付查询订单接口返回参数*/
            /// <summary>
            /// 商户订单号
            /// </summary>
            public string out_trade_no { get; set; }
            /// <summary>
            /// 微信支付订单号
            /// </summary>
            public string transaction_id { get; set; }
            /// <summary>
            /// 交易类型
            /// </summary>
            public string trade_type { get; set; }
            /// <summary>
            /// 交易状态
            /// 交易状态,枚举值:
            ///SUCCESS:支付成功
            ///REFUND:转入退款
            ///NOTPAY:未支付
            ///CLOSED:已关闭
            ///REVOKED:已撤销(付款码支付)
            ///USERPAYING:用户支付中(付款码支付)
            ///PAYERROR:支付失败(其他原因,如银行返回失败)
            /// </summary>
            public string trade_state { get; set; }
            /// <summary>
            /// 交易状态描述
            /// </summary>
            public string trade_state_desc { get; set; }
            /// <summary>
            /// 支付完成时间
            /// </summary>
            public string success_time { get; set; }
            /// <summary>
            /// 支付者
            /// </summary>

            public payPerson payer { get; set; }

            /// <summary>
            /// 订单金额
            /// </summary>

            public ResourceReslt_amount amount { get; set; }
            /*自定义扩展参数*/
            /// <summary>
            /// 返回结果标识(0失败,1成功)
            /// </summary>
            public int code { get; set; }
        }
        /// <summary>
        /// 统一通知数据解析结果金额类
        /// 详情参考:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_5.shtml  
        /// 支付成功通知参数 中 订单金额(amount) 成员
        /// </summary>
        public class ResourceReslt_amount
        {
            /// <summary>
            /// 总金额 订单总金额,单位为分。
            /// </summary>
            public int total { get; set; }
            /// <summary>
            /// 用户支付金额 用户支付金额,单位为分。
            /// </summary>
            public int payer_total { get; set; }
            /// <summary>
            /// 货币类型
            /// </summary>
            public string currency { get; set; } = "CNY";
            /// <summary>
            /// 用户支付币种
            /// </summary>
            public string payer_currency { get; set; } = "CNY";
        }
        /// <summary>
        /// 通用支付者类
        /// 详情参见链接:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_1.shtml
        /// 请求参数中 的 支付者(payer)参数
        /// </summary>
        public class payPerson
        {
            /// <summary>
            /// 用户标识
            /// </summary>
            public string openid { get; set; }
        }
        #endregion
        #region 退款
        /// <summary>
        /// 统一退款请求参数类
        /// 详情参见链接:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_9.shtml 请求参数
        /// </summary>
        private class OutBodyModel
        {
            /// <summary>
            /// 商户订单号 必填
            /// </summary>
            public string out_trade_no { get; set; }
            /// <summary>
            /// 商户退款单号 必填
            /// </summary>
            public string out_refund_no { get; set; }
            /// <summary>
            /// 退款原因 非必填
            /// </summary>
            public string reason { get; set; } = "退款";

            / <summary>
            / 退款结果回调url 非必填
            / </summary>
            //public string notify_url { get; set; } = "";
            /// <summary>
            /// 金额信息 必填
            /// </summary>
            public object amount { get; set; }
        }

        /// <summary>
        /// 统一退款请求参数 金额信息类
        /// 详情参见链接:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_9.shtml 
        /// 请求参数中 的 金额信息(amount)参数
        /// </summary>
        private class Out_amount
        {
            /// <summary>
            /// 退款金额 必填
            /// 退款金额,单位为分,只能为整数,不能超过原订单支付金额。
            /// </summary>
            public int refund { get; set; }
            /// <summary>
            /// 原订单金额 必填
            /// 原支付交易的订单总金额,单位为分,只能为整数。
            /// </summary>
            public int total { get; set; }
            /// <summary>
            /// 退款币种 必填
            /// 符合ISO 4217标准的三位字母代码,目前只支持人民币:CNY。
            /// </summary>
            public string currency { get; set; } = "CNY";
        }

        /// <summary>
        /// 统一退款返回参数类
        /// 请求统一申请退款接口返回参数类
        /// 详情参见链接:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_9.shtml 返回参数
        /// </summary>
        public class Out_result
        {
            /*微信支付申请退款接口返回参数*/
            /// <summary>
            /// 微信支付退款单号 必填
            /// </summary>
            public string refund_id { get; set; }
            /// <summary>
            /// 商户退款单号 必填
            /// </summary>
            public string out_refund_no { get; set; }
            /// <summary>
            /// 微信支付订单号 必填
            /// </summary>
            public string transaction_id { get; set; }

            /// <summary>
            /// 商户订单号 必填
            /// </summary>
            public string out_trade_no { get; set; }
            /// <summary>
            /// 退款渠道 必填
            /// </summary>
            public string channel { get; set; }
            /// <summary>
            /// 退款入账账户 必填
            /// </summary>
            public string user_received_account { get; set; }
            /// <summary>
            /// 退款成功时间 非必填
            /// </summary>
            public string success_time { get; set; }
            /// <summary>
            /// 退款创建时间 必填
            /// </summary>
            public string create_time { get; set; }
            /// <summary>
            /// 退款状态 必填
            /// </summary>
            public string status { get; set; }
            /// <summary>
            /// 资金账户 必填
            /// </summary>
            public string funds_account { get; set; }
            /// <summary>
            /// 金额信息 必填
            /// </summary>
            public Out_result_amount amount { get; set; }
            /*自定义扩展参数*/
            /// <summary>
            /// 状态码:200成功,其他失败
            /// </summary>
            public int code { get; set; } = 400;

        }

        /// <summary>
        /// 统一退款返回参数 金额信息类
        /// 详情参见链接:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_9.shtml 
        /// 返回参数中 的 金额信息(amount)参数
        /// </summary>
        public class Out_result_amount
        {
            /// <summary>
            /// 退款金额 必填
            /// 退款标价金额,单位为分,可以做部分退款
            /// </summary>
            public int refund { get; set; }
            /// <summary>
            /// 订单金额 必填
            /// 订单总金额,单位为分
            /// </summary>
            public int total { get; set; }
            /// <summary>
            /// 用户支付金额 必填
            /// 现金支付金额,单位为分,只能为整数
            /// </summary>
            public int payer_refund { get; set; }
            /// <summary>
            /// 用户退款金额 必填
            /// 退款给用户的金额,不包含所有优惠券金额
            /// </summary>
            public int payer_total { get; set; }

            /// <summary>
            /// 应结退款金额 必填
            /// 去掉非充值代金券退款金额后的退款金额,单位为分,退款金额=申请退款金额-非充值代金券退款金额,退款金额<=申请退款金额
            /// </summary>
            public int settlement_refund { get; set; }
            /// <summary>
            /// 应结订单金额 必填
            /// 应结订单金额=订单金额-免充值代金券金额,应结订单金额<=订单金额,单位为分
            /// </summary>
            public int settlement_total { get; set; }
            /// <summary>
            /// 优惠退款金额 必填
            /// 优惠退款金额<=退款金额,退款金额-代金券或立减优惠退款金额为现金,说明详见代金券或立减优惠,单位为分
            /// </summary>
            public int discount_refund { get; set; }
            /// <summary>
            /// 手续费退款金额 非必填
            /// 手续费退款金额,单位为分。
            /// </summary>
            public int refund_fee { get; set; }

            /// <summary>
            /// 退款币种 必填
            /// 符合ISO 4217标准的三位字母代码,目前只支持人民币:CNY。
            /// </summary>
            public string currency { get; set; } = "CNY";
        }

        #endregion
        #endregion


        #region 公共方法 (已测试上线)(适用于JSAPI、APP、H5、Native、小程序)
        /// <summary>
        /// 统一查询订单接口
        /// 微信支付平台提供的JSAPI统一查询订单接口地址:https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{out_trade_no}
        /// 详情参见:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_2.shtml
        /// </summary>
        /// <param name="out_trade_no">商户平台订单编号 必填</param>
        /// 其他参数更具业务需要自行添加
        /// <returns></returns>
        public async Task<string> SearchOrder(string out_trade_no)
        {
            LogHelper.WriteWithTime("JSAPISearchOrder进入");
            LogHelper.WriteWithTime("mchid:" + mch_id + "out_trade_no" + out_trade_no);
            //签名后发起请求
            HttpClient client = new HttpClient(new HttpHandler(mch_id, certificateKey));
            //请求头部添加Accept参数,值为application/json,固定参数,无需修改
            client.DefaultRequestHeaders.Add("Accept", "application/json");
            //请求头部添加User-Agent参数,值为Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36,固定参数,无需修改
            client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36");
            //发起GET请求并等待结果返回,传入参数为商户平台订单编号和商户号
            var response = await client.GetAsync($@"https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{out_trade_no}" + "?mchid=" + mch_id);
            LogHelper.WriteWithTime("response : " + JsonConvert.SerializeObject(response));
            //等待返回结果读取
            var respStr = await response.Content.ReadAsStringAsync();
            LogHelper.WriteWithTime("respStr : " + JsonConvert.SerializeObject(respStr));
            //创建通知数据解析结果类实例
            ResourceReslt jo = new ResourceReslt();
            if (response.IsSuccessStatusCode)
            {
                //如果IsSuccessStatusCode为成功,则返回订单查询结果
                jo = JsonConvert.DeserializeObject<ResourceReslt>(respStr);
                jo.code = 1;
            }
            else
            {
                //如果IsSuccessStatusCode为失败,则返回失败状态码
                jo.code = 0;
            }
            return JsonConvert.SerializeObject(jo);

        }
        /// <summary>
        /// 统一退款接口
        /// 详情参见:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_9.shtml
        /// </summary>
        /// <param name="out_trade_no">商户订单号</param>
        /// <param name="out_refund_no">商户退款单号(商户系统内部的退款单号,商户系统内部唯一,只能是数字、大小写字母_-|*@ ,同一退款单号多次请求只退一笔。)</param>
        /// <param name="refund">退款金额(元)(退款金额,单位为分,只能为整数,不能超过原订单支付金额。)</param>
        /// <param name="total">订单金额(元)(原支付交易的订单总金额,单位为分,只能为整数。)</param>
        /// 其他参数更具业务需要自行添加
        /// <returns></returns>
        public async Task<string> Refunds(string out_trade_no, string out_refund_no, double refund, double total)
        {
            //创建jsapi返回结果类的实例 returnParameters
            Out_result returnParameters = new Out_result();
            //构建即将发起的POST请求的body参数
            var formData = new OutBodyModel
            {
                out_trade_no = out_trade_no,//商户订单号
                out_refund_no = out_refund_no,//商户退款单号
                amount = new Out_amount
                {
                    total = Convert.ToInt32(total * 100),//订单金额
                    refund = Convert.ToInt32(refund * 100),//退款金额
                }
            };
            LogHelper.WriteWithTime("OutBodyModel : " + JsonConvert.SerializeObject(formData));
            //使用示例:HttpClient client = new HttpClient(new HttpHandler("{商户号}", "{商户证书序列号}"));
            //HttpClient client = new HttpClient(new HttpHandler("1500536401", "340A5D32A5040892B41217F0730EDC5137A76405"));
            HttpClient client = new HttpClient(new HttpHandler(mch_id, certificateKey));
            //请求头部添加Accept参数,值为application/json,固定参数,无需修改
            client.DefaultRequestHeaders.Add("Accept", "application/json");
            //请求头部添加User-Agent参数,值为Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36,固定参数,无需修改
            client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36");
            var bodyJson = new StringContent(JsonConvert.SerializeObject(formData), Encoding.UTF8, "application/json");
            //发起请求并等待请求结果返回
            var response = await client.PostAsync(OutUrl, bodyJson);
            LogHelper.WriteWithTime("response : " + JsonConvert.SerializeObject(response));
            //等待返回结果
            var respStr = await response.Content.ReadAsStringAsync();
            LogHelper.WriteWithTime("respStr : " + JsonConvert.SerializeObject(respStr));

            //JObject jo = (JObject)JsonConvert.DeserializeObject(respStr);
            if (response.IsSuccessStatusCode)
            {
                //如果请求成功将返回的JSON字符串转换为对象
                returnParameters = JsonConvert.DeserializeObject<Out_result>(respStr);
                returnParameters.code = 200;
            }//失败则返回初始化的returnParameters

            //返回returnParameters
            return JsonConvert.SerializeObject(returnParameters);

        }
        /// <summary>
        /// 统一查询单笔退款接口
        /// 微信支付平台提供的JSAPI统一查询订单接口地址:https://api.mch.weixin.qq.com/v3/refund/domestic/refunds/{out_refund_no}
        /// 详情参见:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_10.shtml
        /// </summary>
        /// <param name="out_refund_no">商户平台退款单号 必填</param>
        /// 其他参数更具业务需要自行添加
        /// <returns></returns>
        public async Task<string> SearchRefunds(string out_refund_no)
        {
            LogHelper.WriteWithTime("JSAPISearchOrder进入");
            LogHelper.WriteWithTime("mchid:" + mch_id + "out_trade_no" + out_refund_no);
            //签名后发起请求
            HttpClient client = new HttpClient(new HttpHandler(mch_id, certificateKey));
            //请求头部添加Accept参数,值为application/json,固定参数,无需修改
            client.DefaultRequestHeaders.Add("Accept", "application/json");
            //请求头部添加User-Agent参数,值为Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36,固定参数,无需修改
            client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36");
            //发起GET请求并等待结果返回,传入参数为商户平台订单编号和商户号
            var response = await client.GetAsync($@"https://api.mch.weixin.qq.com/v3/refund/domestic/refunds/{out_refund_no}");
            LogHelper.WriteWithTime("response : " + JsonConvert.SerializeObject(response));
            //等待返回结果读取
            var respStr = await response.Content.ReadAsStringAsync();
            LogHelper.WriteWithTime("respStr : " + JsonConvert.SerializeObject(respStr));
            //创建通知数据解析结果类实例
            Out_result jo = new Out_result();
            if (response.IsSuccessStatusCode)
            {
                //如果IsSuccessStatusCode为成功,则返回订单查询结果
                jo = JsonConvert.DeserializeObject<Out_result>(respStr);
                jo.code = 1;
            }
            else
            {
                //如果IsSuccessStatusCode为失败,则返回失败状态码
                jo.code = 0;
            }
            return JsonConvert.SerializeObject(jo);

        }
        #endregion

        #region JSAPI支付(已完成测试上线)
        #region JSAPI参数
        /// <summary>
        /// 统一下单接口(JSAPI)
        /// 微信支付平台提供的JSAPI统一下单接口地址
        /// </summary>
        private readonly string JSAPIurl = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi";
        #endregion
        #region JSAPI参数类
        /// <summary>
        /// 调起支付参数类
        /// 详情参见链接:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_4.shtml 接口定义
        /// </summary>
        private class JSAPICallUpPaymentParams
        {
            /*微信调起支付要求参数*/
            /// <summary>
            /// 公众号AppId
            /// 商户申请的公众号对应的appid,由微信支付生成,可在公众号后台查看
            /// </summary>
            public string appid { get; set; }
            /// <summary>
            /// 时间戳
            /// 时间戳,标准北京时间,时区为东八区,自1970年1月1日 0点0分0秒以来的秒数。注意:部分系统取到的值为毫秒级,需要转换成秒(10位数字)。
            /// </summary>
            public string timeStamp { get; set; }
            /// <summary>
            /// 随机字符串
            /// 随机字符串,不长于32位。
            /// </summary>
            public string nonceStr { get; set; }
            /// <summary>
            /// 订单详情扩展字符串
            /// JSAPI下单接口返回的prepay_id参数值,提交格式如:prepay_id=***
            /// </summary>
            public string package { get; set; }
            /// <summary>
            /// 签名方式
            /// 签名类型,默认为RSA,仅支持RSA。
            /// 示例值:RSA
            /// </summary>
            public string signType { get; set; }
            /// <summary>
            /// 签名
            /// 使用字段appId、timeStamp、nonceStr、package计算得出的签名值
            /// 签名生成调用Sign()方法
            /// </summary>
            public string paySign { get; set; }
            /*自定义扩展参数*/
            /// <summary>
            /// 商户平台订单号
            /// </summary>
            public string orderCode { get; set; }
            /// <summary>
            /// 返回结果标识(0失败,1成功)
            /// </summary>
            public int code { get; set; }

        }

        /// <summary>
        /// jsapi返回结果类
        /// </summary>
        private class JSAPIreturnParameters : ReturnParametersBase
        {
            /// <summary>
            /// 预支付交易会话标识
            /// 用于后续接口调用中使用,该值有效期为2小时
            /// </summary>
            public string prepay_id { get; set; }
        }
        #region 下单
        /// <summary>
        /// JSAPI下单请求参数类
        /// 详情参见链接:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_1.shtml 请求参数
        /// </summary>
        private class JSAPIbodyModel : PayOrderbodyModelBase
        {
            /// <summary>
            /// 支付者信息
            /// </summary>
            public object payer { get; set; }
        }


        #endregion
        #endregion
        #region JSAPI方法

        /// <summary>
        /// JSAPI调用的统一支付接口
        /// 用户返回前端需要处理的数据内容
        /// 详情参见:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_4.shtml
        /// </summary>
        /// <param name="description">商品描述 必填</param>
        /// <param name="total">商品金额,以“元”为单位 必填</param>
        /// <param name="openid">微信公众号用户openid 必填</param>
        /// <param name="orderCode">商户平台订单编号 必填</param>
        /// 其他参数更具业务需要自行添加
        /// <returns></returns>
        public async Task<object> JsApiPay(string description, decimal total, string openid, string orderCode)
        {
            LogHelper.WriteWithTime("JsApiPay 进入调起支付接口");
            //获取prepay_id
            string resultStr = await JSAPIGetprepay(description, total, orderCode, openid);

            JSAPIreturnParameters result = JsonConvert.DeserializeObject<JSAPIreturnParameters>(resultStr);
            LogHelper.WriteWithTime("resultStr" + resultStr);
            //订单详情扩展字符串
            string prepay_id = "";
            //时间戳
            string timeStamp = "";
            //随机字符串 不长于32位
            string nonceStr = "";
            //微信签名
            string paySign = "";
            //接口返回结果标识(0失败,1成功)
            int code = 0;
            if (result.result)
            {//如果获取prepay_id成功 则执行以下代码
                prepay_id = "prepay_id=" + result.prepay_id;
                //获取时间戳
                timeStamp = GetTimestamp10(DateTime.Now);
                //生成随机字符串
                nonceStr = DateTime.Now.ToString("yyyyMMddHHmmssfff");
                //生成签名字符串
                paySign = Sign(appid + "\n" + timeStamp + "\n" + nonceStr + "\n" + prepay_id + "\n", privateKey);
                //接口返回结果标识设置为成功
                code = 1;
            }
            //返回的结果对象,结果对象内容按照微信支付提供的JSAPI调起支付参数进定义
            JSAPICallUpPaymentParams returnObj = new JSAPICallUpPaymentParams()
            {
                appid = appid,
                timeStamp = timeStamp,
                nonceStr = nonceStr,
                package = prepay_id,
                signType = "RSA",
                paySign = paySign,
                orderCode = orderCode,
                code = code
            };

            return returnObj;
        }
        /// <summary>
        /// JSAPI下单接口
        /// 成功返回prepay_id,失败返回https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi接口错误信息
        /// 详情参见:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_1.shtml
        /// </summary>
        /// <param name="description">商品描述 必填</param>
        /// <param name="total">金额,以“元”为单位 必填</param>
        /// <param name="out_trade_no">商户平台订单号 必填</param>
        /// <param name="openId">微信公众号openid 必填</param>
        /// 其他参数更具业务需要自行添加
        /// <returns></returns>
        private async Task<string> JSAPIGetprepay(string description, decimal total, string out_trade_no, string openId)
        {
            //创建jsapi返回结果类的实例 returnParameters
            JSAPIreturnParameters returnParameters = new JSAPIreturnParameters();
            //构建即将发起的POST请求的body参数
            var formData = new JSAPIbodyModel
            {
                appid = appid,//应用ID
                mchid = mch_id,//商户号
                description = description,//商品描述
                out_trade_no = out_trade_no,//商户订单号
                //attach = attach,//附加数据
                notify_url = notifyurl,//通知地址
                amount = new amount
                {
                    total = Convert.ToInt32(total * 100),//金额
                    currency = "CNY"
                },
                payer = new payPerson()
                {
                    openid = openId
                }
            };
            //使用示例:HttpClient client = new HttpClient(new HttpHandler("{商户号}", "{商户证书序列号}"));
            //HttpClient client = new HttpClient(new HttpHandler("1500536401", "340A5D32A5040892B41217F0730EDC5137A76405"));
            HttpClient client = new HttpClient(new HttpHandler(mch_id, certificateKey));
            //请求头部添加Accept参数,值为application/json,固定参数,无需修改
            client.DefaultRequestHeaders.Add("Accept", "application/json");
            //请求头部添加User-Agent参数,值为Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36,固定参数,无需修改
            client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36");
            var bodyJson = new StringContent(JsonConvert.SerializeObject(formData), Encoding.UTF8, "application/json");
            //发起请求并等待请求结果返回
            var response = await client.PostAsync(JSAPIurl, bodyJson);
            LogHelper.WriteWithTime("response : " + JsonConvert.SerializeObject(response));
            //等待返回结果
            var respStr = await response.Content.ReadAsStringAsync();
            LogHelper.WriteWithTime("respStr : " + JsonConvert.SerializeObject(respStr));
            //将返回的JSON字符串转换为对象
            JObject jo = (JObject)JsonConvert.DeserializeObject(respStr);
            if (response.IsSuccessStatusCode)
            {
                //如果IsSuccessStatusCode为成功,获取请求结果中的prepay_id赋值到returnParameters.prepay_id
                returnParameters.prepay_id = jo["prepay_id"].ToString();
                returnParameters.result = true;
            }
            else
            {
                //如果IsSuccessStatusCode为失败,获取请求结果中的message赋值到returnParameters.errmsg
                returnParameters.errmsg = jo["message"].ToString();
                returnParameters.result = false;
            }
            //返回returnParameters
            return JsonConvert.SerializeObject(returnParameters);

        }

        #endregion
        #endregion

        #region APP支付(完成未测试)
        #region APP参数
        /// <summary>
        /// 统一下单接口(APP)
        /// 微信支付平台提供的APP统一下单接口地址
        /// </summary>
        private readonly string APPUrl = "https://api.mch.weixin.qq.com/v3/pay/transactions/app";
        #endregion
        #region APP参数类
        /// <summary>
        /// 调起支付参数类
        /// 详情参见链接:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_4.shtml 接口定义
        /// </summary>
        private class APPCallUpPaymentParams
        {
            /*微信调起支付要求参数*/
            /// <summary>
            /// 公众号AppId
            /// 商户申请的公众号对应的appid,由微信支付生成,可在公众号后台查看
            /// </summary>
            public string appid { get; set; }
            /// <summary>
            /// 商户号
            /// 请填写商户号mchid对应的值。
            /// </summary>
            public string partnerid { get; set; }
            /// <summary>
            /// 预支付交易会话ID
            /// 微信返回的支付交易会话ID,该值有效期为2小时。
            /// </summary>
            public string prepayid { get; set; }
            /// <summary>
            /// 订单详情扩展字符串
            /// 暂填写固定值Sign=WXPay
            /// </summary>
            public string package { get; set; }
            /// <summary>
            /// 随机字符串
            /// 随机字符串,不长于32位。推荐随机数生成算法。
            /// </summary>
            public string nonceStr { get; set; }
            /// <summary>
            /// 时间戳
            /// 时间戳,标准北京时间,时区为东八区,自1970年1月1日 0点0分0秒以来的秒数。注意:部分系统取到的值为毫秒级,需要转换成秒(10位数字)。
            /// </summary>
            public string timeStamp { get; set; }
            /// <summary>
            /// 签名
            /// 使用字段appId、timeStamp、nonceStr、package计算得出的签名值
            /// 签名生成调用Sign()方法
            /// </summary>
            public string sign { get; set; }
            /*自定义扩展参数*/
            /// <summary>
            /// 商户平台订单号
            /// </summary>
            public string orderCode { get; set; }
            /// <summary>
            /// 返回结果标识(0失败,1成功)
            /// </summary>
            public int code { get; set; }

        }

        /// <summary>
        /// APP返回结果类
        /// </summary>
        private class APPreturnParameters : ReturnParametersBase
        {
            /// <summary>
            /// 预支付交易会话标识
            /// 用于后续接口调用中使用,该值有效期为2小时
            /// </summary>
            public string prepay_id { get; set; }
        }
        #endregion
        #region APP方法

        /// <summary>
        /// APP调用的统一支付接口
        /// 用户返回前端需要处理的数据内容
        /// 详情参见:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_2_4.shtml
        /// </summary>
        /// <param name="description">商品描述 必填</param>
        /// <param name="total">商品金额,以“元”为单位 必填</param>
        /// <param name="orderCode">商户平台订单编号 必填</param>
        /// 其他参数更具业务需要自行添加
        /// <returns></returns>
        public async Task<object> APPPay(string description, decimal total, string orderCode)
        {
            LogHelper.WriteWithTime("APPPay 进入调起支付接口");
            //获取prepay_id
            string resultStr = await APPGetprepay(description, total, orderCode);

            APPreturnParameters result = JsonConvert.DeserializeObject<APPreturnParameters>(resultStr);
            LogHelper.WriteWithTime("resultStr" + resultStr);
            //订单详情扩展字符串
            string prepay_id = "";
            //时间戳
            string timeStamp = "";
            //随机字符串 不长于32位
            string nonceStr = "";
            //微信签名
            string paySign = "";
            //接口返回结果标识(0失败,1成功)
            int code = 0;
            if (result.result)
            {//如果获取prepay_id成功 则执行以下代码
                prepay_id = result.prepay_id;
                //获取时间戳
                timeStamp = GetTimestamp10(DateTime.Now);
                //生成随机字符串
                nonceStr = DateTime.Now.ToString("yyyyMMddHHmmssfff");
                //生成签名字符串
                paySign = Sign(appid + "\n" + timeStamp + "\n" + nonceStr + "\n" + prepay_id + "\n", privateKey);
                //接口返回结果标识设置为成功
                code = 1;
            }
            //返回的结果对象,结果对象内容按照微信支付提供的JSAPI调起支付参数进定义
            APPCallUpPaymentParams returnObj = new APPCallUpPaymentParams()
            {
                appid = appid,
                partnerid = mch_id,
                prepayid = prepay_id,
                package = "Sign=WXPay",
                nonceStr = nonceStr,
                timeStamp = timeStamp,
                sign = paySign,
                orderCode = orderCode,
                code = code
            };

            return returnObj;
        }
        /// <summary>
        /// APP下单接口
        /// 成功返回prepay_id,失败返回https://api.mch.weixin.qq.com/v3/pay/transactions/app接口错误信息
        /// 详情参见:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_2_1.shtml
        /// </summary>
        /// <param name="description">商品描述 必填</param>
        /// <param name="total">金额,以“元”为单位 必填</param>
        /// <param name="out_trade_no">商户平台订单号 必填</param>
        /// 其他参数更具业务需要自行添加
        /// <returns></returns>
        private async Task<string> APPGetprepay(string description, decimal total, string out_trade_no)
        {
            //创建APP返回结果类的实例 returnParameters
            APPreturnParameters returnParameters = new APPreturnParameters();
            //构建即将发起的POST请求的body参数
            var formData = new PayOrderbodyModelBase
            {
                appid = appid,//应用ID
                mchid = mch_id,//商户号
                description = description,//商品描述
                out_trade_no = out_trade_no,//商户订单号
                //attach = attach,//附加数据
                notify_url = notifyurl,//通知地址
                amount = new amount
                {
                    total = Convert.ToInt32(total * 100),//金额
                    currency = "CNY"
                }
            };
            //使用示例:HttpClient client = new HttpClient(new HttpHandler("{商户号}", "{商户证书序列号}"));
            //HttpClient client = new HttpClient(new HttpHandler("1500536401", "340A5D32A5040892B41217F0730EDC5137A76405"));
            HttpClient client = new HttpClient(new HttpHandler(mch_id, certificateKey));
            //请求头部添加Accept参数,值为application/json,固定参数,无需修改
            client.DefaultRequestHeaders.Add("Accept", "application/json");
            //请求头部添加User-Agent参数,值为Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36,固定参数,无需修改
            client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36");
            var bodyJson = new StringContent(JsonConvert.SerializeObject(formData), Encoding.UTF8, "application/json");
            //发起请求并等待请求结果返回
            var response = await client.PostAsync(APPUrl, bodyJson);
            LogHelper.WriteWithTime("response : " + JsonConvert.SerializeObject(response));
            //等待返回结果
            var respStr = await response.Content.ReadAsStringAsync();
            LogHelper.WriteWithTime("respStr : " + JsonConvert.SerializeObject(respStr));
            //将返回的JSON字符串转换为对象
            JObject jo = (JObject)JsonConvert.DeserializeObject(respStr);
            if (response.IsSuccessStatusCode)
            {
                //如果IsSuccessStatusCode为成功,获取请求结果中的prepay_id赋值到returnParameters.prepay_id
                returnParameters.prepay_id = jo["prepay_id"].ToString();
                returnParameters.result = true;
            }
            else
            {
                //如果IsSuccessStatusCode为失败,获取请求结果中的message赋值到returnParameters.errmsg
                returnParameters.errmsg = jo["message"].ToString();
                returnParameters.result = false;
            }
            //返回returnParameters
            return JsonConvert.SerializeObject(returnParameters);

        }

        #endregion
        #endregion

        #region H5支付 (完成未测试)
        #region H5参数
        /// <summary>
        /// 统一下单接口(H5)
        /// 微信支付平台提供的H5统一下单接口地址
        /// </summary>
        public static readonly string H5Url = "https://api.mch.weixin.qq.com/v3/pay/transactions/h5";
        #endregion
        #region H5参数类

        /// <summary>
        /// h5返回结果类
        /// </summary>
        private class H5returnParameters : ReturnParametersBase
        {
            /// <summary>
            /// 支付跳转链接
            /// h5_url为拉起微信支付收银台的中间页面,可通过访问该url来拉起微信客户端,完成支付,h5_url的有效期为5分钟。
            /// </summary>
            public string h5_url { get; set; }
        }
        #region 下单
        /// <summary>
        /// H5下单请求参数类
        /// 详情参见链接:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_3_1.shtml 请求参数
        /// </summary>
        private class H5bodyModel : PayOrderbodyModelBase
        {
            /// <summary>
            /// 场景信息
            /// </summary>
            public object scene_info { get; set; }
        }


        #endregion
        #endregion
        #region H5方法
        /// <summary>
        /// H5下单接口
        /// 成功返回h5_url,失败返回https://api.mch.weixin.qq.com/v3/pay/transactions/h5接口错误信息
        /// 详情参见:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_3_1.shtml
        /// </summary>
        /// <param name="description">商品描述 必填</param>
        /// <param name="total">金额,以“元”为单位 必填</param>
        /// <param name="out_trade_no">商户平台订单号 必填</param>
        /// <param name="payer_client_ip">用户终端IP 用户的客户端IP,支持IPv4和IPv6两种格式的IP地址。 必填</param>
        /// 其他参数更具业务需要自行添加
        /// <returns></returns>
        public async Task<string> H5Getprepay(string description, decimal total, string out_trade_no, string payer_client_ip)
        {
            //创建H5返回结果类的实例 returnParameters
            H5returnParameters returnParameters = new H5returnParameters();
            //构建即将发起的POST请求的body参数
            var formData = new H5bodyModel
            {
                appid = appid,//应用ID
                mchid = mch_id,//商户号
                description = description,//商品描述
                out_trade_no = out_trade_no,//商户订单号
                notify_url = notifyurl,//通知地址
                amount = new amount
                {
                    total = Convert.ToInt32(total * 100),//金额
                    currency = "CNY"
                },
                scene_info = new scene_info()
                {
                    payer_client_ip = payer_client_ip,
                    h5_info = new h5_info()
                    {
                        type = "Wap"
                    }
                }
            };
            //使用示例:HttpClient client = new HttpClient(new HttpHandler("{商户号}", "{商户证书序列号}"));
            //HttpClient client = new HttpClient(new HttpHandler("1500536401", "340A5D32A5040892B41217F0730EDC5137A76405"));
            HttpClient client = new HttpClient(new HttpHandler(mch_id, certificateKey));
            //请求头部添加Accept参数,值为application/json,固定参数,无需修改
            client.DefaultRequestHeaders.Add("Accept", "application/json");
            //请求头部添加User-Agent参数,值为Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36,固定参数,无需修改
            client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36");
            var bodyJson = new StringContent(JsonConvert.SerializeObject(formData), Encoding.UTF8, "application/json");
            //发起请求并等待请求结果返回
            var response = await client.PostAsync(H5Url, bodyJson);
            LogHelper.WriteWithTime("response : " + JsonConvert.SerializeObject(response));
            //等待返回结果
            var respStr = await response.Content.ReadAsStringAsync();
            LogHelper.WriteWithTime("respStr : " + JsonConvert.SerializeObject(respStr));
            //将返回的JSON字符串转换为对象
            JObject jo = (JObject)JsonConvert.DeserializeObject(respStr);
            if (response.IsSuccessStatusCode)
            {
                //如果IsSuccessStatusCode为成功,获取请求结果中的h5_url赋值到returnParameters.h5_url
                returnParameters.h5_url = jo["h5_url"].ToString();
                returnParameters.result = true;
            }
            else
            {
                //如果IsSuccessStatusCode为失败,获取请求结果中的message赋值到returnParameters.errmsg
                returnParameters.errmsg = jo["message"].ToString();
                returnParameters.result = false;
            }
            //返回returnParameters
            return JsonConvert.SerializeObject(returnParameters);

        }

        #endregion
        #endregion

        #region Native支付(完成未测试)
        #region Native参数
        /// <summary>
        /// 统一下单接口(Native)
        /// 微信支付平台提供的Native统一下单接口地址
        /// </summary>
        public static readonly string NativeUrl = "https://api.mch.weixin.qq.com/v3/pay/transactions/native";
        #endregion

        #region Native参数类

        /// <summary>
        /// Native返回结果类
        /// </summary>
        private class NativereturnParameters : ReturnParametersBase
        {
            /// <summary>
            /// 二维码链接
            /// 此URL用于生成支付二维码,然后提供给用户扫码支付。
            /// </summary>
            public string code_url { get; set; }
        }

        #region Native方法
        /// <summary>
        /// Native下单接口
        /// 成功返回code_url,失败返回https://api.mch.weixin.qq.com/v3/pay/transactions/native接口错误信息
        /// 详情参见:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_3_1.shtml
        /// </summary>
        /// <param name="description">商品描述 必填</param>
        /// <param name="total">金额,以“元”为单位 必填</param>
        /// <param name="out_trade_no">商户平台订单号 必填</param>
        /// 其他参数更具业务需要自行添加
        /// <returns></returns>
        public async Task<string> NativeGetprepay(string description, decimal total, string out_trade_no)
        {
            //创建Nativere返回结果类的实例 returnParameters
            NativereturnParameters returnParameters = new NativereturnParameters();
            //构建即将发起的POST请求的body参数
            var formData = new PayOrderbodyModelBase
            {
                appid = appid,//应用ID
                mchid = mch_id,//商户号
                description = description,//商品描述
                out_trade_no = out_trade_no,//商户订单号
                notify_url = notifyurl,//通知地址
                amount = new amount
                {
                    total = Convert.ToInt32(total * 100),//金额
                    currency = "CNY"
                }
            };
            //使用示例:HttpClient client = new HttpClient(new HttpHandler("{商户号}", "{商户证书序列号}"));
            //HttpClient client = new HttpClient(new HttpHandler("1500536401", "340A5D32A5040892B41217F0730EDC5137A76405"));
            HttpClient client = new HttpClient(new HttpHandler(mch_id, certificateKey));
            //请求头部添加Accept参数,值为application/json,固定参数,无需修改
            client.DefaultRequestHeaders.Add("Accept", "application/json");
            //请求头部添加User-Agent参数,值为Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36,固定参数,无需修改
            client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36");
            var bodyJson = new StringContent(JsonConvert.SerializeObject(formData), Encoding.UTF8, "application/json");
            //发起请求并等待请求结果返回
            var response = await client.PostAsync(NativeUrl, bodyJson);
            LogHelper.WriteWithTime("response : " + JsonConvert.SerializeObject(response));
            //等待返回结果
            var respStr = await response.Content.ReadAsStringAsync();
            LogHelper.WriteWithTime("respStr : " + JsonConvert.SerializeObject(respStr));
            //将返回的JSON字符串转换为对象
            JObject jo = (JObject)JsonConvert.DeserializeObject(respStr);
            if (response.IsSuccessStatusCode)
            {
                //如果IsSuccessStatusCode为成功,获取请求结果中的code_url转换成二维码的base64编码赋值到returnParameters.code_url
                try
                {
                    var TheImage = QRCoderHelper.GetQRCode(jo["code_url"].ToString(), 4);
                    String base64 = String.Empty;
                    if (TheImage != null)
                    {
                        MemoryStream stream = new MemoryStream();
                        TheImage.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp);
                        byte[] bytes = stream.ToArray();
                        stream.Close();
                        base64 = Convert.ToBase64String(bytes);
                    }
                    returnParameters.code_url = "data:image/png;base64," + base64;
                    returnParameters.result = true;
                }
                catch (Exception ex)
                {

                    throw;
                }



            }
            else
            {
                //如果IsSuccessStatusCode为失败,获取请求结果中的message赋值到returnParameters.errmsg
                returnParameters.errmsg = jo["message"].ToString();
                returnParameters.result = false;
            }
            //返回returnParameters
            return JsonConvert.SerializeObject(returnParameters);

        }

        #endregion
        #endregion
        #endregion





        #region 通用方法
        /// <summary>
        /// 获取时间戳10位(秒)
        /// </summary>
        /// <param name="dateTime"></param>
        /// <returns></returns>
        public string GetTimestamp10(DateTime dateTime)
        {
            return ((dateTime.ToUniversalTime().Ticks - 621355968000000000) / 10000000).ToString();
        }
        /// <summary>
        /// 通用签名方法
        /// </summary>
        /// <param name="message">签名内容</param>
        /// <param name="privateKey">商户私钥</param>
        /// 调用示例:string paySign = Sign(appid + "\n" + timeStamp + "\n" + nonceStr + "\n" + prepay_id + "\n", privateKey);
        /// <returns></returns>
        public string Sign(string message, string privateKey)
        {
            byte[] keyData = Convert.FromBase64String(privateKey);
            using CngKey cngKey = CngKey.Import(keyData, CngKeyBlobFormat.Pkcs8PrivateBlob);
            using RSACng rsa = new RSACng(cngKey);
            byte[] data = System.Text.Encoding.UTF8.GetBytes(message);
            return Convert.ToBase64String(rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
        }
        #endregion

        #region 解密类
        /// <summary>
        /// 解密类
        /// 用于解密微信回调商户平台提供的回调接口时传输的加密报文
        /// 详情参见:https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_2.shtml .NET示例代码
        /// </summary>
        public class AesGcm
        {
            private static string ALGORITHM = "AES/GCM/NoPadding";
            private static int TAG_LENGTH_BIT = 128;
            private static int NONCE_LENGTH_BYTE = 12;
            private static string AES_KEY = wxPayApiKey;//APIv3密钥
            /// <summary>
            /// 报文解密方法
            /// 参数内容参见:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_5.shtml 参数解密
            /// </summary>
            /// <param name="associatedData">附加数据</param>
            /// <param name="nonce">随机串 加密使用的随机串</param>
            /// <param name="ciphertext">数据密文 Base64编码后的开启/停用结果数据密文</param>
            /// <returns></returns>
            public static string AesGcmDecrypt(string associatedData, string nonce, string ciphertext)
            {
                GcmBlockCipher gcmBlockCipher = new GcmBlockCipher(new AesEngine());
                AeadParameters aeadParameters = new AeadParameters(
                    new KeyParameter(Encoding.UTF8.GetBytes(AES_KEY)),
                    128,
                    Encoding.UTF8.GetBytes(nonce),
                    Encoding.UTF8.GetBytes(associatedData));
                gcmBlockCipher.Init(false, aeadParameters);

                byte[] data = Convert.FromBase64String(ciphertext);
                byte[] plaintext = new byte[gcmBlockCipher.GetOutputSize(data.Length)];
                int length = gcmBlockCipher.ProcessBytes(data, 0, data.Length, plaintext, 0);
                gcmBlockCipher.DoFinal(plaintext, length);
                return Encoding.UTF8.GetString(plaintext);
            }


        }
        #endregion
    }
    /// <summary>
    /// 微信支付 支付,退款接口参数
    /// </summary>
    public class WXApiParams
    {
        /// <summary>
        /// 支付描述
        /// </summary>
        public string description { get; set; }
        /// <summary>
        /// 订单金额(元)
        /// </summary>
        public decimal total { get; set; }
        /// <summary>
        /// 平台订单号
        /// </summary>
        public  string out_trade_no { get; set; }
        /// <summary>
        /// 微信公众平台OPENID
        /// </summary>
        public string  openId { get; set; }
        /// <summary>
        /// 退款金额(元)
        /// </summary>
        public decimal refund { get; set; }
        /// <summary>
        /// 对应业务表主键
        /// </summary>
        public string F_BusinessId { get; set; }
        /// <summary>
        /// 创建人用户ID
        /// </summary>
        public string F_CreatorUserId { get; set; }
        /// <summary>
        /// 物业公司表主键ID
        /// </summary>
        public string F_PropertyId { get; set; }
        /// <summary>
        /// 订单类型 1为商超,2为餐饮,3物业费
        /// </summary>
        public int orderType { get; set; }
        /// <summary>
        /// 退款类型:1为商家退款,2为居民申请退款
        /// </summary>
        public int refundType { get; set; }
    }
}

HTTP处理类

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace WaterCloud.Code.Web
{
    /// <summary>
    /// Http处理程序
    /// 此类为官方提供内容,此处不做任何修改
    /// 用于在请求微信接口时对请求构建签名信息,调用方式参照以下示例
    /// 使用方法:
    /// HttpClient client = new HttpClient(new HttpHandler("{商户号}", "{商户证书序列号}"));
    /// ...
    /// var response = client.GetAsync("https://api.mch.weixin.qq.com/v3/certificates");
    /// 官方文档参考:https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_0.shtml .NET示例代码
    /// </summary>
    public class HttpHandler : DelegatingHandler
    {
        private readonly string merchantId;
        private readonly string serialNo;
        /// <summary>
        /// HttpHandler构造函数
        /// </summary>
        /// <param name="merchantId">商户号</param>
        /// <param name="merchantSerialNo">商户证书序列号</param>
        public HttpHandler(string merchantId, string merchantSerialNo)
        {
            InnerHandler = new HttpClientHandler();

            this.merchantId = merchantId;
            this.serialNo = merchantSerialNo;
        }
        /// <summary>
        /// 发送请求方法
        /// </summary>
        /// <param name="request"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        protected async override Task<HttpResponseMessage> SendAsync(
            HttpRequestMessage request,
            CancellationToken cancellationToken)
        {
            var auth = await BuildAuthAsync(request);
            string value = $"WECHATPAY2-SHA256-RSA2048 {auth}";
            request.Headers.Add("Authorization", value);

            return await base.SendAsync(request, cancellationToken);
        }
        /// <summary>
        /// 创建签名方法
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        protected async Task<string> BuildAuthAsync(HttpRequestMessage request)
        {
            string method = request.Method.ToString();
            string body = "";
            if (method == "POST" || method == "PUT" || method == "PATCH")
            {
                var content = request.Content;
                body = await content.ReadAsStringAsync();
            }

            string uri = request.RequestUri.PathAndQuery;
            var timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
            string nonce = Path.GetRandomFileName();

            string message = $"{method}\n{uri}\n{timestamp}\n{nonce}\n{body}\n";
            string signature = Sign(message);
            return $"mchid=\"{merchantId}\",nonce_str=\"{nonce}\",timestamp=\"{timestamp}\",serial_no=\"{serialNo}\",signature=\"{signature}\"";
        }
        /// <summary>
        /// 请求签名方法
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        protected string Sign(string message)
        {

            //直接调用WXPayHelper中配置的商户私钥privateKey
            string privateKey = WXPayHelper.privateKey;
            byte[] keyData = Convert.FromBase64String(privateKey);

            var rsa = RSA.Create();
            //适用该方法的版本https://learn.microsoft.com/zh-cn/dotnet/api/system.security.cryptography.asymmetricalgorithm.importpkcs8privatekey?view=net-7.0
            rsa.ImportPkcs8PrivateKey(keyData, out _);
            byte[] data = System.Text.Encoding.UTF8.GetBytes(message);
            return Convert.ToBase64String(rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
        }
    }
}

 二维码生成类

using QRCoder;
using System.Drawing;
using System.Drawing.Imaging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WaterCloud.Code.Web
{
    /// <summary>
    /// 二维码生成类
    /// </summary>
    public static class QRCoderHelper
    {
        /// <summary>
        /// 生成二维码
        /// </summary>
        /// <param name="url">存储内容</param>
        /// <param name="pixel">像素大小</param>
        /// <returns></returns>
        public static Bitmap GetQRCode(string url, int pixel)
        {
            QRCodeGenerator generator = new QRCodeGenerator();
            QRCodeData codeData = generator.CreateQrCode(url, QRCodeGenerator.ECCLevel.M, true);
            QRCode qrcode = new QRCode(codeData);
            Bitmap qrImage = qrcode.GetGraphic(pixel, Color.Black, Color.White, true);

            return qrImage;
        }

    }
}

注:二维码生成类需要引用包QRCoder

使用方法

        创建项目后复制代码创建类文件,根据提示安装缺失的包。微信支付类使用时根据业务场景修改接口参数。

微信支付回调示例

/// <summary>
/// 统一微信回调地址
/// 详情参见:
/// 支付结果通知:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_5.shtml
/// 用于微信平台调用商户平台的回调方法,在支付成功后微信会调用商户平台该方法,处理相关业务逻辑
/// </summary>
/// <returns></returns>
public async Task<string> WXCallback()
{
    //创建回调方法返回对象
    object reslut = new { code = "FAIL", message = "失败" };
    LogHelper.WriteWithTime("WXCallback进入");
    //创建支付结果通知类实例
    WXPayHelper.PayResult payResult = new WXPayHelper.PayResult();
    try
    {

        Stream stream = HttpContext.Request.Body;
        byte[] buffer = new byte[HttpContext.Request.ContentLength.Value];
        await stream.ReadAsync(buffer, 0, buffer.Length); //.net core 3.1需要用ReadAsync才不会出错
        string str = System.Text.Encoding.UTF8.GetString(buffer);
        JObject jsonObj = JObject.Parse(str);
        //将参数内容json字符串结果转换为支付结果通知类对象
        payResult = JsonConvert.DeserializeObject<WXPayHelper.PayResult>(str);

        LogHelper.WriteWithTime("PayResult" + JsonConvert.SerializeObject(payResult));

        if (payResult.event_type.Equals("TRANSACTION.SUCCESS"))
        {
            //如果支付通知结果中的通知类型event_type为"TRANSACTION.SUCCESS",处理成功后的业务逻辑
            LogHelper.WriteWithTime("信息接收状态成功");
            //调用Aes报文解密方法解密数据报文
            var dataJson = WXPayHelper.AesGcm.AesGcmDecrypt(payResult.resource.associated_data, payResult.resource.nonce, payResult.resource.ciphertext);
            LogHelper.WriteWithTime("dataJson" + dataJson);
            //转换解密后的报文字符串为通知数据解析结果类对象
            WXPayHelper.ResourceReslt data = JsonConvert.DeserializeObject<WXPayHelper.ResourceReslt>(dataJson);
            if (data.trade_state.Equals("SUCCESS"))
            {
                /*
                * 当解析结果内容中的交易状态trade_state为"SUCCESS"时
                * 自己的业务逻辑 开始
                */
                LogHelper.WriteWithTime("交易状态成功");
                Response.StatusCode = 200;
                reslut = new { code = "SUCCESS", message = "成功" };
                /*
                * 自己的业务逻辑 结束
                */
            }

        }
        else
        {
            //打印日志
            LogHelper.WriteWithTime("PayResult" + JsonConvert.SerializeObject(payResult));
            Response.StatusCode = 500;
        }
    }
    catch (Exception ex)
    {
        LogHelper.WriteWithTime("异常信息:" + ex.Message);
        Response.StatusCode = 500;
        return JsonConvert.SerializeObject(reslut);
    }

    return JsonConvert.SerializeObject(reslut);
}

下单调用示例

/// 生成订单号
/// </summary>
/// <returns></returns>
public string getRandomTime()
{
    Random rd = new Random();//用于生成随机数
    string DateStr = DateTime.Now.ToString("yyyyMMddHHmmssMM");//日期
    string str = DateStr + rd.Next(10000).ToString().PadLeft(4, '0');//带日期的随机数
    return str;
}

/// <summary>
/// 前端调用的统一支付接口
/// 返回前端需要处理的数据内容
/// 前端提取到数据后需要处理数据并调起支付,前端调起支付参考文件:项目更目录下 /Demo/微信调起支付前端代码.txt
/// </summary>
/// <param name="description">商品描述 必填</param>
/// <param name="total">商品金额,以“元”为单位 必填</param>
/// <param name="openid">微信公众号用户openid 必填</param>
/// 其他参数更具业务场景自行定义
/// <returns></returns>
public async Task<object> JsApiPay(string description, decimal total, string openid)
{
    LogHelper.WriteWithTime("JsApiPay 进入调起支付接口");
    /*
     * 自定义生成未支付完成订单的业务逻辑 开始
     */
    //生成订单编号
    string orderCode = getRandomTime();
    /*
     * 自定义生成未支付完成订单的业务逻辑 结束
     */

    //返回JSAPI调用的统一支付接口执行结果
    return await new WXPayHelper().JsApiPay(description, total, openid, orderCode);

}

退款示例

/// <summary>
/// 前后端调用的统一申请退款接口
/// </summary>
/// <param name="orderCode">商户平台订单编号</param>
/// 其他参数更具业务场景自行定义
/// <returns></returns>
public async Task<object> PayRefunds(string orderCode)
{
    //创建返回对象
    object reslut = new { code = "FAIL", message = "失败" };
    LogHelper.WriteWithTime("JsApiPayRefunds 进入");


    /*
     * 更具具体业务场景编写根据传入的商户平台订单编号orderCode查询订单信息业务逻辑
     * 自己的业务逻辑 开始
     */



    /*
     * 自己的业务逻辑 结束
     */


    /*
     * 调用JSAPI申请退款接口接口
     * 根据自己查询的订单信息按照接口参数要求传入参数即可
     * 调用示例await new WXPayHelper().JSAPIRefunds("订单号","退款单号(手动生成,要求编号唯一)",退款金额(类型为double,单位为元),订单金额(类型为double,单位为元));
     */
    string resultStr = await new WXPayHelper().Refunds(orderCode, "手动生成的退款单号", 0.01, 0.01);//使用时修改接口参数!!!!!!


    //转换返回的JSON字符串为 JSAPI退款返回参数类 对象
    WXPayHelper.Out_result data = JsonConvert.DeserializeObject<WXPayHelper.Out_result>(resultStr);
    if (data != null)
    {
        //如果解析结果不为null,且退款状态status值为成功SUCCESS/退款处理中PROCESSING,
        if (!string.IsNullOrEmpty(data.status) && (data.status.Equals("SUCCESS") || data.status.Equals("PROCESSING")))
        {
            /*
             * 且退款状态status值为成功SUCCESS/退款处理中PROCESSING时
             * 自己的业务逻辑 开始
             */



            /*
             * 自己的业务逻辑 结束
             */
            reslut = new { code = "SUCCESS", message = "成功" };
        }
        else
        {
            /*
             * 且退款状态status值为退款关闭CLOSED/退款异常ABNORMAL时
             * 自己的业务逻辑 开始
             */



            /*
             * 自己的业务逻辑 结束
             */
        }
    }


    return reslut;

}

订单查询

/// <summary>
/// 前端调用的统一查询订单接口
/// </summary>
/// <param name="orderCode">商户平台订单编号</param>
/// 其他参数更具业务场景自行定义
/// <returns></returns>
public async Task<object> PayDownSearch(string orderCode)
{
    //创建返回对象
    object reslut = new { code = "FAIL", message = "失败" };
    LogHelper.WriteWithTime("JsApiPayDownSearch 进入");
    //调用JSAPI查询订单接口
    string resultStr = await new WXPayHelper().SearchOrder(orderCode);
    //转换返回的JSON字符串为 通知数据解析结果类 对象
    WXPayHelper.ResourceReslt data = JsonConvert.DeserializeObject<WXPayHelper.ResourceReslt>(resultStr);
    if (data != null)
    {
        //如果解析结果不为null
        if (!string.IsNullOrEmpty(data.trade_state) && data.trade_state.Equals("SUCCESS"))
        {
            /*
             * 如果解析结果中的交易状态trade_state不为null或空字符串,且状态为"SUCCESS"时
             * 自己的业务逻辑 开始
             */



            /*
             * 自己的业务逻辑 结束
             */
            reslut = new { code = "SUCCESS", message = "成功" };
        }
        else
        {
            /*
             * 如果解析结果中的交易状态trade_state状态不为成功时
             * 自己的业务逻辑 开始
             */



            /*
             * 自己的业务逻辑 结束
             */
        }
    }


    return reslut;

}

退款订单查询

/// <summary>
/// 前端调用的统一查询单笔退款接口
/// </summary>
/// <param name="out_refund_no">商户平台订单编号</param>
/// 其他参数更具业务场景自行定义
/// <returns></returns>
public async Task<object> PaySearchRefunds(string out_refund_no)
{
    //创建返回对象
    object reslut = new { code = "FAIL", message = "失败" };
    LogHelper.WriteWithTime("JsApiPaySearchRefunds 进入");
    //调用JSAPI查询单笔退款接口
    string resultStr = await new WXPayHelper().SearchRefunds(out_refund_no);
    //转换返回的JSON字符串为 JSAPI退款返回参数类 对象
    WXPayHelper.Out_result data = JsonConvert.DeserializeObject<WXPayHelper.Out_result>(resultStr);
    if (data != null)
    {
        //如果解析结果不为null
        if (!string.IsNullOrEmpty(data.status) && data.status.Equals("SUCCESS"))
        {
            /*
             * 如果解析结果中的退款状态status不为null或空字符串,且状态为"SUCCESS"时
             * 自己的业务逻辑 开始
             */



            /*
             * 自己的业务逻辑 结束
             */
            reslut = new { code = "SUCCESS", message = "成功" };
        }
        else
        {
            /*
             * 如果解析结果中的交易状态status状态不为成功时
             * 自己的业务逻辑 开始
             */



            /*
             * 自己的业务逻辑 结束
             */
        }
    }


    return reslut;

}

  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值