最近做了下微信支付,坑好多了,最终还是做完了,避免下次再走坑,在此总结一下

配置类

public class Config{//=======【基本信息设置】=====================================/* 微信公众号信息配置* APPID:绑定支付的APPID(必须配置)* MCHID:商户号(必须配置)* KEY:商户支付密钥,参考开户邮件设置(必须配置),请妥善保管,避免密钥泄露* APPSECRET:公众帐号secert(仅JSAPI支付的时候需要配置),请妥善保管,避免密钥泄露*/public static string AppID{get { return ConfigurationManager.AppSettings["AppID"]; }}public static string MchID{get { return ConfigurationManager.AppSettings["MchID"]; }}public static string Key{get { return ConfigurationManager.AppSettings["Key"]; }}public static string AppSecret{get { return ConfigurationManager.AppSettings["AppSecret"]; }}//=======【证书路径设置】===================================== /* 证书路径,注意应该填写绝对路径(仅退款、撤销订单时需要)* 1.证书文件不能放在web服务器虚拟目录,应放在有访问权限控制的目录中,防止被他人下载;* 2.建议将证书文件名改为复杂且不容易猜测的文件* 3.商户服务器要做好病毒和木马防护工作,不被非法侵入者窃取证书文件。*/public static string SSlCertPath{get { return ConfigurationManager.AppSettings["SSlCertPath"]; }}public static string SSlCertPassword{get { return ConfigurationManager.AppSettings["SSlCertPassword"]; }}//=======【支付结果通知url】===================================== /* 支付结果通知回调url,用于商户接收支付结果*/public static string NotifyUrl{get { return ConfigurationManager.AppSettings["NotifyUrl"]; }}//=======【商户系统后台机器IP】===================================== /* 此参数可手动配置也可在程序中自动获取*/public static string Ip{get { return ConfigurationManager.AppSettings["Ip"]; }}//=======【代理服务器设置】===================================/* 默认IP和端口号分别为0.0.0.0和0,此时不开启代理(如有需要才设置)*/public static string ProxyUrl{get { return ConfigurationManager.AppSettings["ProxyUrl"]; }}//=======【上报信息配置】===================================/* 测速上报等级,0.关闭上报; 1.仅错误时上报; 2.全量上报*/public static int ReportLevel{get{int rl = 0;int.TryParse(ConfigurationManager.AppSettings["ReportLevel"], out rl);return rl;}}}

接口数据处理帮助类

    /// <summary>/// 微信支付协议接口数据类,所有的API接口通信都依赖这个数据结构,/// 在调用接口之前先填充各个字段的值,然后进行接口通信,/// 这样设计的好处是可扩展性强,用户可随意对协议进行更改而不用重新设计数据结构,/// 还可以随意组合出不同的协议数据包,不用为每个协议设计一个数据包结构/// </summary>public class WxPayData{public  const string SIGN_TYPE_MD5 = "MD5";public  const string SIGN_TYPE_HMAC_SHA256 = "HMAC-SHA256";public WxPayData(){}//采用排序的Dictionary的好处是方便对数据包进行签名,不用再签名之前再做一次排序private SortedDictionary<string, object> m_values = new SortedDictionary<string, object>();/*** 设置某个字段的值* @param key 字段名* @param value 字段值*/public void SetValue(string key, object value){m_values[key] = value;}/*** 根据字段名获取某个字段的值* @param key 字段名* @return key对应的字段值*/public object GetValue(string key){object o = null;m_values.TryGetValue(key, out o);return o;}/*** 判断某个字段是否已设置* @param key 字段名* @return 若字段key已被设置,则返回true,否则返回false*/public bool IsSet(string key){object o = null;m_values.TryGetValue(key, out o);if (null != o)return true;elsereturn false;}/*** @将Dictionary转成xml* @return 经转换得到的xml串* @throws WxPayException**/public string ToXml(){//数据为空时不能转化为xml格式if (0 == m_values.Count){Log.Error(this.GetType().ToString(), "WxPayData数据为空!");throw new WxPayException("WxPayData数据为空!");}string xml = "<xml>";foreach (KeyValuePair<string, object> pair in m_values){//字段值不能为null,会影响后续流程if (pair.Value == null){Log.Error(this.GetType().ToString(), "WxPayData内部含有值为null的字段!");throw new WxPayException("WxPayData内部含有值为null的字段!");}if (pair.Value.GetType() == typeof(int)){xml += "<" + pair.Key + ">" + pair.Value + "</" + pair.Key + ">";}else if (pair.Value.GetType() == typeof(string)){xml += "<" + pair.Key + ">" + "<![CDATA[" + pair.Value + "]]></" + pair.Key + ">";}else//除了string和int类型不能含有其他数据类型{Log.Error(this.GetType().ToString(), "WxPayData字段数据类型错误!");throw new WxPayException("WxPayData字段数据类型错误!");}}xml += "</xml>";return xml;}/*** @将xml转为WxPayData对象并返回对象内部的数据* @param string 待转换的xml串* @return 经转换得到的Dictionary* @throws WxPayException*/public SortedDictionary<string, object> FromXml(string xml){if (string.IsNullOrEmpty(xml)){Log.Error(this.GetType().ToString(), "将空的xml串转换为WxPayData不合法!");throw new WxPayException("将空的xml串转换为WxPayData不合法!");}SafeXmlDocument xmlDoc = new SafeXmlDocument();xmlDoc.LoadXml(xml);XmlNode xmlNode = xmlDoc.FirstChild;//获取到根节点<xml>XmlNodeList nodes = xmlNode.ChildNodes;foreach (XmlNode xn in nodes){XmlElement xe = (XmlElement)xn;m_values[xe.Name] = xe.InnerText;//获取xml的键值对到WxPayData内部的数据中}try{//2015-06-29 错误是没有签名if(m_values["return_code"] != "SUCCESS"){return m_values;}CheckSign();//验证签名,不通过会抛异常}catch(WxPayException ex){throw new WxPayException(ex.Message);}return m_values;}/*** @Dictionary格式转化成url参数格式* @ return url格式串, 该串不包含sign字段值*/public string ToUrl(){string buff = "";foreach (KeyValuePair<string, object> pair in m_values){if (pair.Value == null){Log.Error(this.GetType().ToString(), "WxPayData内部含有值为null的字段!");throw new WxPayException("WxPayData内部含有值为null的字段!");}if (pair.Key != "sign" && pair.Value.ToString() != ""){buff += pair.Key + "=" + pair.Value + "&";}}buff = buff.Trim('&');return buff;}/*** @Dictionary格式化成Json* @return json串数据*/public string ToJson(){string jsonStr = JsonMapper.ToJson(m_values);return jsonStr;}/*** @values格式化成能在Web页面上显示的结果(因为web页面上不能直接输出xml格式的字符串)*/public string ToPrintStr(){string str = "";foreach (KeyValuePair<string, object> pair in m_values){if (pair.Value == null){Log.Error(this.GetType().ToString(), "WxPayData内部含有值为null的字段!");throw new WxPayException("WxPayData内部含有值为null的字段!");}str += string.Format("{0}={1}\n", pair.Key, pair.Value.ToString());}str = HttpUtility.HtmlEncode(str);Log.Debug(this.GetType().ToString(), "Print in Web Page : " + str);return str;}/*** @生成签名,详见签名生成算法* @return 签名, sign字段不参加签名*/public string MakeSign(string signType){//转url格式string str = ToUrl();//在string后加入API KEYstr += "&key=" + WxPayConfig.GetConfig().GetKey();if (signType == SIGN_TYPE_MD5){var md5 = MD5.Create();var bs = md5.ComputeHash(Encoding.UTF8.GetBytes(str));var sb = new StringBuilder();foreach (byte b in bs){sb.Append(b.ToString("x2"));}//所有字符转为大写return sb.ToString().ToUpper();}else if(signType==SIGN_TYPE_HMAC_SHA256){return CalcHMACSHA256Hash(str, WxPayConfig.GetConfig().GetKey());}else{throw new WxPayException("sign_type 不合法");}}/*** @生成签名,详见签名生成算法* @return 签名, sign字段不参加签名 SHA256*/public string MakeSign(){return MakeSign(SIGN_TYPE_HMAC_SHA256);}/*** * 检测签名是否正确* 正确返回true,错误抛异常*/public bool CheckSign(string signType){//如果没有设置签名,则跳过检测if (!IsSet("sign")){Log.Error(this.GetType().ToString(), "WxPayData签名存在但不合法!");throw new WxPayException("WxPayData签名存在但不合法!");}//如果设置了签名但是签名为空,则抛异常else if (GetValue("sign") == null || GetValue("sign").ToString() == ""){Log.Error(this.GetType().ToString(), "WxPayData签名存在但不合法!");throw new WxPayException("WxPayData签名存在但不合法!");}//获取接收到的签名string return_sign = GetValue("sign").ToString();//在本地计算新的签名string cal_sign = MakeSign(signType);if (cal_sign == return_sign){return true;}Log.Error(this.GetType().ToString(), "WxPayData签名验证错误!");throw new WxPayException("WxPayData签名验证错误!");}/*** * 检测签名是否正确* 正确返回true,错误抛异常*/public bool CheckSign(){return CheckSign(SIGN_TYPE_HMAC_SHA256);}/*** @获取Dictionary*/public SortedDictionary<string, object> GetValues(){return m_values;}private  string CalcHMACSHA256Hash(string plaintext, string salt){string result = "";var enc = Encoding.Default;byte[]baText2BeHashed = enc.GetBytes(plaintext),baSalt = enc.GetBytes(salt);System.Security.Cryptography.HMACSHA256 hasher = new HMACSHA256(baSalt);byte[] baHashedText = hasher.ComputeHash(baText2BeHashed);result = string.Join("", baHashedText.ToList().Select(b => b.ToString("x2")).ToArray());return result;}}

底层通讯类

/// <summary>/// http连接基础类,负责底层的http通信/// </summary>public class HttpService{private static string USER_AGENT = string.Format("WXPaySDK/{3} ({0}) .net/{1} {2}", Environment.OSVersion, Environment.Version, Config.MchID, typeof(HttpService).Assembly.GetName().Version);public static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors){//直接确认,否则打不开    return true;}public static string Post(string xml, string url, bool isUseCert, int timeout){System.GC.Collect();//垃圾回收,回收没有正常关闭的http连接string result = "";//返回结果HttpWebRequest request = null;HttpWebResponse response = null;Stream reqStream = null;try{//设置最大连接数ServicePointManager.DefaultConnectionLimit = 200;//设置https验证方式if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase)){ServicePointManager.ServerCertificateValidationCallback =new RemoteCertificateValidationCallback(CheckValidationResult);}/**************************************************************** 下面设置HttpWebRequest的相关属性* ************************************************************/request = (HttpWebRequest)WebRequest.Create(url);request.UserAgent = USER_AGENT;request.Method = "POST";request.Timeout = timeout * 1000;//设置代理服务器if (!string.IsNullOrEmpty(Config.ProxyUrl)){WebProxy proxy = new WebProxy();                          //定义一个网关对象proxy.Address = new Uri(Config.ProxyUrl);              //网关服务器端口:端口request.Proxy = proxy;}//设置POST的数据类型和长度request.ContentType = "text/xml";byte[] data = System.Text.Encoding.UTF8.GetBytes(xml);request.ContentLength = data.Length;//是否使用证书if (isUseCert){string path = HttpContext.Current.Request.PhysicalApplicationPath;X509Certificate2 cert = new X509Certificate2(path + Config.SSlCertPath, Config.SSlCertPassword);request.ClientCertificates.Add(cert);//Log.Debug("WxPayApi", "PostXml used cert");}//往服务器写入数据reqStream = request.GetRequestStream();reqStream.Write(data, 0, data.Length);reqStream.Close();//获取服务端返回response = (HttpWebResponse)request.GetResponse();//获取服务端返回数据StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);result = sr.ReadToEnd().Trim();sr.Close();}catch (System.Threading.ThreadAbortException e){//Log.Error("HttpService", "Thread - caught ThreadAbortException - resetting.");//Log.Error("Exception message: {0}", e.Message);System.Threading.Thread.ResetAbort();}catch (WebException e){//Log.Error("HttpService", e.ToString());if (e.Status == WebExceptionStatus.ProtocolError){//Log.Error("HttpService", "StatusCode : " + ((HttpWebResponse)e.Response).StatusCode);//Log.Error("HttpService", "StatusDescription : " + ((HttpWebResponse)e.Response).StatusDescription);}throw new Exception(e.ToString());}catch (Exception e){//Log.Error("HttpService", e.ToString());throw new Exception(e.ToString());}finally{//关闭连接和流if (response != null){response.Close();}if (request != null){request.Abort();}}return result;}/// <summary>/// 处理http GET请求,返回数据/// </summary>/// <param name="url">请求的url地址</param>/// <returns>http GET成功后返回的数据,失败抛WebException异常</returns>public static string Get(string url){System.GC.Collect();string result = "";HttpWebRequest request = null;HttpWebResponse response = null;//请求url以获取数据try{//设置最大连接数ServicePointManager.DefaultConnectionLimit = 200;//设置https验证方式if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase)){ServicePointManager.ServerCertificateValidationCallback =new RemoteCertificateValidationCallback(CheckValidationResult);}/**************************************************************** 下面设置HttpWebRequest的相关属性* ************************************************************/request = (HttpWebRequest)WebRequest.Create(url);request.UserAgent = USER_AGENT;request.Method = "GET";//获取服务器返回response = (HttpWebResponse)request.GetResponse();//获取HTTP返回数据StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);result = sr.ReadToEnd().Trim();sr.Close();}catch (System.Threading.ThreadAbortException e){//Log.Error("HttpService","Thread - caught ThreadAbortException - resetting.");//Log.Error("Exception message: {0}", e.Message);System.Threading.Thread.ResetAbort();}catch (WebException e){//Log.Error("HttpService", e.ToString());if (e.Status == WebExceptionStatus.ProtocolError){// Log.Error("HttpService", "StatusCode : " + ((HttpWebResponse)e.Response).StatusCode);//Log.Error("HttpService", "StatusDescription : " + ((HttpWebResponse)e.Response).StatusDescription);}throw new Exception(e.ToString());}catch (Exception e){//Log.Error("HttpService", e.ToString());throw new Exception(e.ToString());}finally{//关闭连接和流if (response != null){response.Close();}if (request != null){request.Abort();}}return result;}}

回调处理类,这里加了兼容H5支付的情况,spbill_create_ip H5要求传支付用户的真实IP

/// <summary>/// 回调处理基类/// 主要负责接收微信支付后台发送过来的数据,对数据进行签名验证/// 子类在此类基础上进行派生并重写自己的回调处理过程/// </summary>public class Notify{/// <summary>/// 接收从微信支付后台发送过来的数据并验证签名/// </summary>/// <returns>微信支付后台返回的数据</returns>public WxPayData GetNotifyData(HttpContext context){//接收从微信后台POST过来的数据System.IO.Stream s = context.Request.InputStream;int count = 0;byte[] buffer = new byte[1024];StringBuilder builder = new StringBuilder();while ((count = s.Read(buffer, 0, 1024)) > 0){builder.Append(Encoding.UTF8.GetString(buffer, 0, count));}s.Flush();s.Close();s.Dispose();//Log.Info(this.GetType().ToString(), "Receive data from WeChat : " + builder.ToString());//转换数据格式, 取消签名校验,签名调用方自己调用,兼容支付和退款WxPayData data = new WxPayData();try{//FormXML会校验签名data.FromXmlNoCheck(builder.ToString());}catch (Exception ex){//若签名错误,则立即返回结果给微信支付后台WxPayData res = new WxPayData();res.SetValue("return_code", "FAIL");res.SetValue("return_msg", ex.Message);//Log.Error(this.GetType().ToString(), "Sign check error : " + res.ToXml());context.Response.Write(res.ToXml());context.Response.End();}//Log.Info(this.GetType().ToString(), "Check sign success");return data;}//派生类需要重写这个方法,进行不同的回调处理public virtual WxPayData ProcessNotify(HttpContext context){return null;}}

随机数

public class RandomGenerator{readonly RNGCryptoServiceProvider csp;public RandomGenerator(){csp = new RNGCryptoServiceProvider();}public int Next(int minValue, int maxExclusiveValue){if (minValue >= maxExclusiveValue)throw new ArgumentOutOfRangeException("minValue must be lower than maxExclusiveValue");long diff = (long)maxExclusiveValue - minValue;long upperBound = uint.MaxValue / diff * diff;uint ui;do{ui = GetRandomUInt();} while (ui >= upperBound);return (int)(minValue + (ui % diff));}public uint GetRandomUInt(){var randomBytes = GenerateRandomBytes(sizeof(uint));return BitConverter.ToUInt32(randomBytes, 0);}private byte[] GenerateRandomBytes(int bytesNumber){byte[] buffer = new byte[bytesNumber];csp.GetBytes(buffer);return buffer;}}

底层方法,这里跟微信源码有点不一样,多加了H5支付的兼容代码

 public class WxPayApi{/*** 提交被扫支付API* 收银员使用扫码设备读取微信用户刷卡授权码以后,二维码或条码信息传送至商户收银台,* 由商户收银台或者商户后台调用该接口发起支付。* @param WxPayData inputObj 提交给被扫支付API的参数* @param int timeOut 超时时间* @throws WxPayException* @return 成功时返回调用结果,其他抛异常*/public static WxPayData Micropay(WxPayData inputObj, int timeOut = 10){string url = "https://api.mch.weixin.qq.com/pay/micropay";//检测必填参数if (!inputObj.IsSet("body")){throw new Exception("提交被扫支付API接口中,缺少必填参数body!");}else if (!inputObj.IsSet("out_trade_no")){throw new Exception("提交被扫支付API接口中,缺少必填参数out_trade_no!");}else if (!inputObj.IsSet("total_fee")){throw new Exception("提交被扫支付API接口中,缺少必填参数total_fee!");}else if (!inputObj.IsSet("auth_code")){throw new Exception("提交被扫支付API接口中,缺少必填参数auth_code!");}inputObj.SetValue("spbill_create_ip", Config.Ip);//终端ipinputObj.SetValue("appid", Config.AppID);//公众账号IDinputObj.SetValue("mch_id", Config.MchID);//商户号inputObj.SetValue("nonce_str", Guid.NewGuid().ToString().Replace("-", ""));//随机字符串inputObj.SetValue("sign_type", WxPayData.SIGN_TYPE_HMAC_SHA256);//签名类型inputObj.SetValue("sign", inputObj.MakeSign());//签名string xml = inputObj.ToXml();var start = DateTime.Now;//请求开始时间//Log.Debug("WxPayApi", "MicroPay request : " + xml);string response = HttpService.Post(xml, url, false, timeOut);//调用HTTP通信接口以提交数据到API//Log.Debug("WxPayApi", "MicroPay response : " + response);var end = DateTime.Now;int timeCost = (int)((end - start).TotalMilliseconds);//获得接口耗时//将xml格式的结果转换为对象以返回WxPayData result = new WxPayData();result.FromXml(response);ReportCostTime(url, timeCost, result);//测速上报return result;}/***    * 查询订单* @param WxPayData inputObj 提交给查询订单API的参数* @param int timeOut 超时时间* @throws WxPayException* @return 成功时返回订单查询结果,其他抛异常*/public static WxPayData OrderQuery(WxPayData inputObj, int timeOut = 6){string url = "https://api.mch.weixin.qq.com/pay/orderquery";//检测必填参数if (!inputObj.IsSet("out_trade_no") && !inputObj.IsSet("transaction_id")){throw new Exception("订单查询接口中,out_trade_no、transaction_id至少填一个!");}inputObj.SetValue("appid", Config.AppID);//公众账号IDinputObj.SetValue("mch_id", Config.MchID);//商户号inputObj.SetValue("nonce_str", WxPayApi.GenerateNonceStr());//随机字符串inputObj.SetValue("sign_type", WxPayData.SIGN_TYPE_HMAC_SHA256);//签名类型inputObj.SetValue("sign", inputObj.MakeSign());//签名string xml = inputObj.ToXml();var start = DateTime.Now;//Log.Debug("WxPayApi", "OrderQuery request : " + xml);string response = HttpService.Post(xml, url, false, timeOut);//调用HTTP通信接口提交数据//Log.Debug("WxPayApi", "OrderQuery response : " + response);var end = DateTime.Now;int timeCost = (int)((end - start).TotalMilliseconds);//获得接口耗时//将xml格式的数据转化为对象以返回WxPayData result = new WxPayData();result.FromXml(response);ReportCostTime(url, timeCost, result);//测速上报return result;}/*** * 撤销订单API接口* @param WxPayData inputObj 提交给撤销订单API接口的参数,out_trade_no和transaction_id必填一个* @param int timeOut 接口超时时间* @throws WxPayException* @return 成功时返回API调用结果,其他抛异常*/public static WxPayData Reverse(WxPayData inputObj, int timeOut = 6){string url = "https://api.mch.weixin.qq.com/secapi/pay/reverse";//检测必填参数if (!inputObj.IsSet("out_trade_no") && !inputObj.IsSet("transaction_id")){throw new Exception("撤销订单API接口中,参数out_trade_no和transaction_id必须填写一个!");}inputObj.SetValue("appid", Config.AppID);//公众账号IDinputObj.SetValue("mch_id", Config.MchID);//商户号inputObj.SetValue("nonce_str", GenerateNonceStr());//随机字符串inputObj.SetValue("sign_type", WxPayData.SIGN_TYPE_HMAC_SHA256);//签名类型inputObj.SetValue("sign", inputObj.MakeSign());//签名string xml = inputObj.ToXml();var start = DateTime.Now;//请求开始时间//Log.Debug("WxPayApi", "Reverse request : " + xml);string response = HttpService.Post(xml, url, true, timeOut);//Log.Debug("WxPayApi", "Reverse response : " + response);var end = DateTime.Now;int timeCost = (int)((end - start).TotalMilliseconds);WxPayData result = new WxPayData();result.FromXml(response);ReportCostTime(url, timeCost, result);//测速上报return result;}/*** * 申请退款* @param WxPayData inputObj 提交给申请退款API的参数* @param int timeOut 超时时间* @throws WxPayException* @return 成功时返回接口调用结果,其他抛异常*/public static WxPayData Refund(WxPayData inputObj, int timeOut = 6){string url = "https://api.mch.weixin.qq.com/secapi/pay/refund";//检测必填参数if (!inputObj.IsSet("out_trade_no") && !inputObj.IsSet("transaction_id")){throw new Exception("退款申请接口中,out_trade_no、transaction_id至少填一个!");}else if (!inputObj.IsSet("out_refund_no")){throw new Exception("退款申请接口中,缺少必填参数out_refund_no!");}else if (!inputObj.IsSet("total_fee")){throw new Exception("退款申请接口中,缺少必填参数total_fee!");}else if (!inputObj.IsSet("refund_fee")){throw new Exception("退款申请接口中,缺少必填参数refund_fee!");}else if (!inputObj.IsSet("op_user_id")){throw new Exception("退款申请接口中,缺少必填参数op_user_id!");}inputObj.SetValue("appid", Config.AppID);//公众账号IDinputObj.SetValue("mch_id", Config.MchID);//商户号inputObj.SetValue("nonce_str", Guid.NewGuid().ToString().Replace("-", ""));//随机字符串//异步通知url未设置,则使用配置文件中的urlif (!inputObj.IsSet("notify_url")){inputObj.SetValue("notify_url", Config.NotifyUrl);//异步通知url}inputObj.SetValue("sign_type", WxPayData.SIGN_TYPE_HMAC_SHA256);//签名类型inputObj.SetValue("sign", inputObj.MakeSign());//签名string xml = inputObj.ToXml();var start = DateTime.Now;//Log.Debug("WxPayApi", "Refund request : " + xml);string response = HttpService.Post(xml, url, true, timeOut);//调用HTTP通信接口提交数据到API//Log.Debug("WxPayApi", "Refund response : " + response);var end = DateTime.Now;int timeCost = (int)((end - start).TotalMilliseconds);//获得接口耗时//将xml格式的结果转换为对象以返回WxPayData result = new WxPayData();result.FromXml(response);ReportCostTime(url, timeCost, result);//测速上报return result;}/*** * 查询退款* 提交退款申请后,通过该接口查询退款状态。退款有一定延时,* 用零钱支付的退款20分钟内到账,银行卡支付的退款3个工作日后重新查询退款状态。* out_refund_no、out_trade_no、transaction_id、refund_id四个参数必填一个* @param WxPayData inputObj 提交给查询退款API的参数* @param int timeOut 接口超时时间* @throws WxPayException* @return 成功时返回,其他抛异常*/public static WxPayData RefundQuery(WxPayData inputObj, int timeOut = 6){string url = "https://api.mch.weixin.qq.com/pay/refundquery";//检测必填参数if (!inputObj.IsSet("out_refund_no") && !inputObj.IsSet("out_trade_no") &&!inputObj.IsSet("transaction_id") && !inputObj.IsSet("refund_id")){throw new Exception("退款查询接口中,out_refund_no、out_trade_no、transaction_id、refund_id四个参数必填一个!");}inputObj.SetValue("appid", Config.AppID);//公众账号IDinputObj.SetValue("mch_id", Config.MchID);//商户号inputObj.SetValue("nonce_str", GenerateNonceStr());//随机字符串inputObj.SetValue("sign_type", WxPayData.SIGN_TYPE_HMAC_SHA256);//签名类型inputObj.SetValue("sign", inputObj.MakeSign());//签名string xml = inputObj.ToXml();var start = DateTime.Now;//请求开始时间//Log.Debug("WxPayApi", "RefundQuery request : " + xml);string response = HttpService.Post(xml, url, false, timeOut);//调用HTTP通信接口以提交数据到API//Log.Debug("WxPayApi", "RefundQuery response : " + response);var end = DateTime.Now;int timeCost = (int)((end - start).TotalMilliseconds);//获得接口耗时//将xml格式的结果转换为对象以返回WxPayData result = new WxPayData();result.FromXml(response);ReportCostTime(url, timeCost, result);//测速上报return result;}/*** 下载对账单* @param WxPayData inputObj 提交给下载对账单API的参数* @param int timeOut 接口超时时间* @throws WxPayException* @return 成功时返回,其他抛异常*/public static WxPayData DownloadBill(WxPayData inputObj, int timeOut = 6){string url = "https://api.mch.weixin.qq.com/pay/downloadbill";//检测必填参数if (!inputObj.IsSet("bill_date")){throw new Exception("对账单接口中,缺少必填参数bill_date!");}inputObj.SetValue("appid", Config.AppID);//公众账号IDinputObj.SetValue("mch_id", Config.MchID);//商户号inputObj.SetValue("nonce_str", GenerateNonceStr());//随机字符串inputObj.SetValue("sign_type", WxPayData.SIGN_TYPE_HMAC_SHA256);//签名类型inputObj.SetValue("sign", inputObj.MakeSign());//签名string xml = inputObj.ToXml();//Log.Debug("WxPayApi", "DownloadBill request : " + xml);string response = HttpService.Post(xml, url, false, timeOut);//调用HTTP通信接口以提交数据到API//Log.Debug("WxPayApi", "DownloadBill result : " + response);WxPayData result = new WxPayData();//若接口调用失败会返回xml格式的结果if (response.Substring(0, 5) == "<xml>"){result.FromXml(response);}//接口调用成功则返回非xml格式的数据elseresult.SetValue("result", response);return result;}/*** * 转换短链接* 该接口主要用于扫码原生支付模式一中的二维码链接转成短链接(weixin://wxpay/s/XXXXXX),* 减小二维码数据量,提升扫描速度和精确度。* @param WxPayData inputObj 提交给转换短连接API的参数* @param int timeOut 接口超时时间* @throws WxPayException* @return 成功时返回,其他抛异常*/public static WxPayData ShortUrl(WxPayData inputObj, int timeOut = 6){string url = "https://api.mch.weixin.qq.com/tools/shorturl";//检测必填参数if (!inputObj.IsSet("long_url")){throw new Exception("需要转换的URL,签名用原串,传输需URL encode!");}inputObj.SetValue("appid", Config.AppID);//公众账号IDinputObj.SetValue("mch_id", Config.MchID);//商户号inputObj.SetValue("nonce_str", GenerateNonceStr());//随机字符串  inputObj.SetValue("sign_type", WxPayData.SIGN_TYPE_HMAC_SHA256);//签名类型inputObj.SetValue("sign", inputObj.MakeSign());//签名string xml = inputObj.ToXml();var start = DateTime.Now;//请求开始时间//Log.Debug("WxPayApi", "ShortUrl request : " + xml);string response = HttpService.Post(xml, url, false, timeOut);//Log.Debug("WxPayApi", "ShortUrl response : " + response);var end = DateTime.Now;int timeCost = (int)((end - start).TotalMilliseconds);WxPayData result = new WxPayData();result.FromXml(response);ReportCostTime(url, timeCost, result);//测速上报return result;}/*** * 统一下单* @param WxPaydata inputObj 提交给统一下单API的参数* @param int timeOut 超时时间* @throws WxPayException* @return 成功时返回,其他抛异常*/public static WxPayData UnifiedOrder(WxPayData inputObj, int timeOut = 6){string url = "https://api.mch.weixin.qq.com/pay/unifiedorder";//检测必填参数if (!inputObj.IsSet("out_trade_no")){throw new Exception("缺少统一支付接口必填参数out_trade_no!");}else if (!inputObj.IsSet("body")){throw new Exception("缺少统一支付接口必填参数body!");}else if (!inputObj.IsSet("total_fee")){throw new Exception("缺少统一支付接口必填参数total_fee!");}else if (!inputObj.IsSet("trade_type")){throw new Exception("缺少统一支付接口必填参数trade_type!");}//关联参数if (inputObj.GetValue("trade_type").ToString() == "JSAPI" && !inputObj.IsSet("openid")){throw new Exception("统一支付接口中,缺少必填参数openid!trade_type为JSAPI时,openid为必填参数!");}if (inputObj.GetValue("trade_type").ToString() == "NATIVE" && !inputObj.IsSet("product_id")){throw new Exception("统一支付接口中,缺少必填参数product_id!trade_type为JSAPI时,product_id为必填参数!");}//异步通知url未设置,则使用配置文件中的urlif (!inputObj.IsSet("notify_url")){inputObj.SetValue("notify_url", Config.NotifyUrl);//异步通知url}inputObj.SetValue("appid", Config.AppID);//公众账号IDinputObj.SetValue("mch_id", Config.MchID);//商户号//若终端IP未设置,则使用配置文件中的终端IPif (!inputObj.IsSet("spbill_create_ip")){inputObj.SetValue("spbill_create_ip", Config.Ip);//终端ip }inputObj.SetValue("nonce_str", GenerateNonceStr());//随机字符串inputObj.SetValue("sign_type", WxPayData.SIGN_TYPE_HMAC_SHA256);//签名类型//签名inputObj.SetValue("sign", inputObj.MakeSign());string xml = inputObj.ToXml();var start = DateTime.Now;// Log.Debug("WxPayApi", "UnfiedOrder request : " + xml);string response = HttpService.Post(xml, url, false, timeOut);//Log.Debug("WxPayApi", "UnfiedOrder response : " + response);var end = DateTime.Now;int timeCost = (int)((end - start).TotalMilliseconds);WxPayData result = new WxPayData();result.FromXml(response);ReportCostTime(url, timeCost, result);//测速上报return result;}/*** * 关闭订单* @param WxPayData inputObj 提交给关闭订单API的参数* @param int timeOut 接口超时时间* @throws WxPayException* @return 成功时返回,其他抛异常*/public static WxPayData CloseOrder(WxPayData inputObj, int timeOut = 6){string url = "https://api.mch.weixin.qq.com/pay/closeorder";//检测必填参数if (!inputObj.IsSet("out_trade_no")){throw new Exception("关闭订单接口中,out_trade_no必填!");}inputObj.SetValue("appid", Config.AppID);//公众账号IDinputObj.SetValue("mch_id", Config.MchID);//商户号inputObj.SetValue("nonce_str", GenerateNonceStr());//随机字符串      inputObj.SetValue("sign_type", WxPayData.SIGN_TYPE_HMAC_SHA256);//签名类型inputObj.SetValue("sign", inputObj.MakeSign());//签名string xml = inputObj.ToXml();var start = DateTime.Now;//请求开始时间string response = HttpService.Post(xml, url, false, timeOut);var end = DateTime.Now;int timeCost = (int)((end - start).TotalMilliseconds);WxPayData result = new WxPayData();result.FromXml(response);ReportCostTime(url, timeCost, result);//测速上报return result;}/*** * 测速上报* @param string interface_url 接口URL* @param int timeCost 接口耗时* @param WxPayData inputObj参数数组*/private static void ReportCostTime(string interface_url, int timeCost, WxPayData inputObj){//如果不需要进行上报if (Config.ReportLevel == 0){return;}如果仅失败上报if (Config.ReportLevel == 1 && inputObj.IsSet("return_code") && inputObj.GetValue("return_code").ToString() == "SUCCESS" &&inputObj.IsSet("result_code") && inputObj.GetValue("result_code").ToString() == "SUCCESS"){return;}//上报逻辑WxPayData data = new WxPayData();data.SetValue("interface_url", interface_url);data.SetValue("execute_time_", timeCost);//返回状态码if (inputObj.IsSet("return_code")){data.SetValue("return_code", inputObj.GetValue("return_code"));}//返回信息if (inputObj.IsSet("return_msg")){data.SetValue("return_msg", inputObj.GetValue("return_msg"));}//业务结果if (inputObj.IsSet("result_code")){data.SetValue("result_code", inputObj.GetValue("result_code"));}//错误代码if (inputObj.IsSet("err_code")){data.SetValue("err_code", inputObj.GetValue("err_code"));}//错误代码描述if (inputObj.IsSet("err_code_des")){data.SetValue("err_code_des", inputObj.GetValue("err_code_des"));}//商户订单号if (inputObj.IsSet("out_trade_no")){data.SetValue("out_trade_no", inputObj.GetValue("out_trade_no"));}//设备号if (inputObj.IsSet("device_info")){data.SetValue("device_info", inputObj.GetValue("device_info"));}try{Report(data);}catch (Exception){//不做任何处理}}/*** * 测速上报接口实现* @param WxPayData inputObj 提交给测速上报接口的参数* @param int timeOut 测速上报接口超时时间* @throws WxPayException* @return 成功时返回测速上报接口返回的结果,其他抛异常*/public static WxPayData Report(WxPayData inputObj, int timeOut = 1){string url = "https://api.mch.weixin.qq.com/payitil/report";//检测必填参数if (!inputObj.IsSet("interface_url")){throw new Exception("接口URL,缺少必填参数interface_url!");}if (!inputObj.IsSet("return_code")){throw new Exception("返回状态码,缺少必填参数return_code!");}if (!inputObj.IsSet("result_code")){throw new Exception("业务结果,缺少必填参数result_code!");}if (!inputObj.IsSet("user_ip")){throw new Exception("访问接口IP,缺少必填参数user_ip!");}if (!inputObj.IsSet("execute_time_")){throw new Exception("接口耗时,缺少必填参数execute_time_!");}inputObj.SetValue("appid", Config.AppID);//公众账号IDinputObj.SetValue("mch_id", Config.MchID);//商户号inputObj.SetValue("user_ip", Config.Ip);//终端ipinputObj.SetValue("time", DateTime.Now.ToString("yyyyMMddHHmmss"));//商户上报时间  inputObj.SetValue("nonce_str", GenerateNonceStr());//随机字符串inputObj.SetValue("sign_type", WxPayData.SIGN_TYPE_HMAC_SHA256);//签名类型inputObj.SetValue("sign", inputObj.MakeSign());//签名string xml = inputObj.ToXml();//Log.Info("WxPayApi", "Report request : " + xml);string response = HttpService.Post(xml, url, false, timeOut);//Log.Info("WxPayApi", "Report response : " + response);WxPayData result = new WxPayData();result.FromXml(response);return result;}/*** 根据当前系统时间加随机序列来生成订单号* @return 订单号*///public static string GenerateOutTradeNo()//{//    var ran = new Random();//    return string.Format("{0}{1}{2}", Config.MchID, DateTime.Now.ToString("yyyyMMddHHmmss"), ran.Next(999));//}/*** 生成时间戳,标准北京时间,时区为东八区,自1970年1月1日 0点0分0秒以来的秒数* @return 时间戳*/public static string GenerateTimeStamp(){TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);return Convert.ToInt64(ts.TotalSeconds).ToString();}/*** 生成随机串,随机串包含字母或数字* @return 随机串*/public static string GenerateNonceStr(){RandomGenerator randomGenerator = new RandomGenerator();return randomGenerator.GetRandomUInt().ToString();}}

转JSON那,微信用的是LitJson,项目实际用的是Newtonsoft.Json,因为多封装了一层,所以WxPayData就用了微信源码,具体根据项目情况再改一改就好了,基础帮助没什么坑,按照实际情况改下就好了

C#微信支付(一)—— 基础帮助类相关推荐

  1. Android 集成微信支付和支付宝支付工具类

    Android 集成微信支付和支付宝支付工具类 1.前言 去年年底接了一个商城app 外包项目,里面尼涉及到 微信和支付宝支付,这里我整理出几个工具类,下面就和大家分享一下,废话不多说,下面我一步一步 ...

  2. iOS微信支付接入以及工具类封装

    在刚刚结束的一个项目中用到了微信支付,从接入微信支付到工具类的封装,在本文中做个积累,方便日后使用. 1.开始接入微信支付的准备工作 首先你需要去微信开放平台注册账号,在这里要吐槽一下,不知道这个微信 ...

  3. 微信支付AES解密工具类

    WechatAESUtil类 public class WechatAESUtil {/*** 密钥算法*/private static final String ALGORITHM = " ...

  4. 实例:用C#.NET手把手教你做微信公众号开发(20)--使用微信支付线上收款:jsapi方式

    在做线上.线下销售时,可以使用微信便捷支付,通过微信公众号收款有很多种收款方式,如下图: 今天我们来讲一下jsapi支付,场景就是在微信内打开某个页面,完成在线支付,同样一个网页,使用微信打开就是js ...

  5. 2022微信支付v3 - Native

    Native支付介绍 参考文档:https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_7_0.shtml Native支付是指商户系统按 ...

  6. unity 微信支付

    转载一下我chen哥的博客 Unity接入微信APP支付(超详细) 前言 微信app支付流程 申请权限&配置app信息 导Unity使用的Jar包 Android开发环境部署 SDK 导出Ja ...

  7. 微会动微信现场互动:微信公众平台基础知识2019修订版

    现在是2019年2月14日,距离2011年1月21日,腾讯推出微信已过去8年:距离2012年8月23日,微信公众平台上线已过去近7年:距离2017年1月9日,微信小程序上线已过去2年. 8年前微信改变 ...

  8. Payment Spring Boot 1.0.2.RELEASE 发布,接入微信支付分、先享卡功能

    Payment Spring Boot 是微信支付V3的Java实现,仅仅依赖Spring内置的一些类库.配置简单方便,可以让开发者快速为Spring Boot应用接入微信支付. 演示例子:https ...

  9. Android 集成微信支付详解

    打包后才能起调支付 微信支付成功起调 微信skd下载:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=11_1 签名APK下载:h ...

最新文章

  1. Excel VBA 教程
  2. 网络工程师考试部分技术要点
  3. 分享一个轻型ORM--Dapper选用理由
  4. java web 播放音频_使用Java ME以流形式播放Web服务器上的音乐文件
  5. SAP从视图获得数据
  6. 把dataframe删掉第一行_python – 从Pandas DataFrame中的所有行中减去第一行
  7. 百度贴吧前负责人:做产品16年,我有9条心得[转]
  8. Idea Tomcat启动报异常CannotLoadBeanClassException
  9. 三极管稳压管组成的线性电源关键理解
  10. mysql分页查询报错,及解决
  11. 【转载保存】接口的压力测试工具
  12. 如何从零搭建一个hexo博客网站01
  13. 苹果延期中国零售商店的重新开业时间 线上商店依旧正常工作
  14. [CTO札记]电纸书,将成为教学、阅读潮流
  15. 纯css3特效实现的文字亮光
  16. 分享一些 Windows 平台上的神器
  17. TFT工业串口屏方案
  18. 费马定理、罗尔中值定理、零点存在定理、拉格朗日中值定理、
  19. 【源码】日历转换器:格里高利历、波斯历和伊斯兰历法
  20. Springboot定时任务【多线程处理】

热门文章

  1. 视通科技分布式系统赋能人民检察院指挥中心建设
  2. 第16届 IEEE 极限编程大赛 参赛记录
  3. Python装逼代码
  4. UE4 在游戏运行时显示或隐藏鼠标
  5. 数据分析(3)——数据描述
  6. 设计人士参加的论坛,自然要有格调的开场形式_数字体验_新浪博客
  7. bootstrap学习(一)-CSS
  8. 以中国传统的孔子和老子的思想来分析忍者代码
  9. DialogInterface.OnClickListener和View.OnClickListener
  10. 通过路由器端口转发实现外网访问内网主机