V3 微信支付-预支付C#

时间:2022-10-25 11:20:30

首先不得不吐槽下腾讯,升级微信支付为毛不兼容V2版本呢?V2算是白研究了。


 

 V3预支付文档几个坑,不知道你们有没有中招

  1. 商户号 mch_id 是 String(32) 微信支付分配的商户号   其实是邮件的“微信支付商户号(接口文档中的商户号MCHID)” ,我一直都以为是商户号。
  2. 预支付提交的xml节点值都必须带有<![CDATA[]]>,如果根据文档开发只带部分。那么你就开心了,一直都是sign签名错误。

回到正文,以下为实现代码

public class PaymentHandler : RequestHandler
{

public PaymentHandler(HttpContext context)
:
base(context, WX_V3_CONFIG.config.PartnerKey)
{

}

/// <summary>
/// 获取预支付订单号
/// </summary>
/// <returns></returns>
public string GetUnifiedOrder(string body, string openid, string trade_type)
{

base.setParameter("appid", WX_V3_CONFIG.config.AppID);
base.setParameter("mch_id", WX_V3_CONFIG.config.MCHID);
base.setParameter("nonce_str", TenpayUtil.getNoncestr());
base.setParameter("body", body);
base.setParameter("out_trade_no", TenpayUtil.getOrderNo());
base.setParameter("total_fee", "1");
base.setParameter("spbill_create_ip", "192.168.1.1");//base.httpContext.Request.UserHostAddress);
base.setParameter("notify_url", "www.111.com");
base.setParameter("trade_type", "JSAPI");
base.setParameter("openid", openid);
base.createSign();

string s = HttpHelper.OpenReadWithHttps("https://api.mch.weixin.qq.com/pay/unifiedorder", base.parseXML());//post请求

return "";
}
}

RequestHandler帮助类

/// <summary>
/// RequestHandler 的摘要说明。
/// </summary>
public class RequestHandler
{

public RequestHandler(HttpContext httpContext, string key)
{
parameters
= new Hashtable();
this.key = key;
this.httpContext = httpContext;

}
/** 密钥 */
private string key;

protected HttpContext httpContext;

/** 请求的参数 */
protected Hashtable parameters;

/** debug信息 */
private string debugInfo;

/** 初始化函数 */
public virtual void init()
{
}
/** 获取debug信息 */
public String getDebugInfo()
{
return debugInfo;
}
/** 获取密钥 */
public String getKey()
{
return key;
}

/** 设置密钥 */
public void setKey(string key)
{
this.key = key;
}

/** 设置参数值 */
public void setParameter(string parameter, string parameterValue)
{
if (parameter != null && parameter != "")
{
if (parameters.Contains(parameter))
{
parameters.Remove(parameter);
}

parameters.Add(parameter, parameterValue);
}
}

/** 获取参数值 */
public string getParameter(string parameter)
{
string s = (string)parameters[parameter];
return (null == s) ? "" : s;
}

//获取package带参数的签名包
public string getRequestURL()
{
this.createSign();
StringBuilder sb
= new StringBuilder();
ArrayList akeys
= new ArrayList(parameters.Keys);
akeys.Sort();
foreach (string k in akeys)
{
string v = (string)parameters[k];
if (null != v && "key".CompareTo(k) != 0)
{
sb.Append(k
+ "=" + TenpayUtil.UrlEncode(v, getCharset()) + "&");
}
}

//去掉最后一个&
if (sb.Length > 0)
{
sb.Remove(sb.Length
- 1, 1);
}


return sb.ToString();

}


//创建md5摘要,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。

protected virtual void createSign()
{
StringBuilder sb
= new StringBuilder();

ArrayList akeys
= new ArrayList(parameters.Keys);
akeys.Sort();

foreach (string k in akeys)
{
string v = (string)parameters[k];
if (null != v && "".CompareTo(v) != 0
&& "sign".CompareTo(k) != 0 && "key".CompareTo(k) != 0)
{
sb.Append(k
+ "=" + v + "&");
}
}

sb.Append(
"key=" + this.getKey());
string sign = MD5Util.GetMD5(sb.ToString(), getCharset()).ToUpper();

this.setParameter("sign", sign);

//debug信息
this.setDebugInfo(sb.ToString() + " => sign:" + sign);
}


//创建package签名
public virtual string createMd5Sign()
{
StringBuilder sb
= new StringBuilder();
ArrayList akeys
= new ArrayList(parameters.Keys);
akeys.Sort();

foreach (string k in akeys)
{
string v = (string)parameters[k];
if (null != v && "".CompareTo(v) != 0
&& "sign".CompareTo(k) != 0 && "".CompareTo(v) != 0)
{
sb.Append(k
+ "=" + v + "&");
}
}
string sign = MD5Util.GetMD5(sb.ToString(), getCharset()).ToLower();

this.setParameter("sign", sign);
return sign;
}


//创建sha1签名
public string createSHA1Sign()
{
StringBuilder sb
= new StringBuilder();
ArrayList akeys
= new ArrayList(parameters.Keys);
akeys.Sort();

foreach (string k in akeys)
{
string v = (string)parameters[k];
if (null != v && "".CompareTo(v) != 0
&& "sign".CompareTo(k) != 0 && "key".CompareTo(k) != 0)
{
if (sb.Length == 0)
{
sb.Append(k
+ "=" + v);
}
else
{
sb.Append(
"&" + k + "=" + v);
}
}
}
string paySign = SHA1Util.getSha1(sb.ToString()).ToString().ToLower();

//debug信息
this.setDebugInfo(sb.ToString() + " => sign:" + paySign);
return paySign;
}


//输出XML
public string parseXML()
{
StringBuilder sb
= new StringBuilder();
sb.Append(
"<xml>");
foreach (string k in parameters.Keys)
{
string v = (string)parameters[k];
if (Regex.IsMatch(v, @"^[0-9.]$"))
{

sb.Append(
"<" + k + ">" + v + "</" + k + ">");
}
else
{
sb.Append(
"<" + k + "><![CDATA[" + v + "]]></" + k + ">");
}

}
sb.Append(
"</xml>");
return sb.ToString();
}



/** 设置debug信息 */
public void setDebugInfo(String debugInfo)
{
this.debugInfo = debugInfo;
}

public Hashtable getAllParameters()
{
return this.parameters;
}

protected virtual string getCharset()
{
return this.httpContext.Request.ContentEncoding.BodyName;
}
}