微信支付V2 统一下单 .NET CORE
一个小功能总是拖拖拖。。唉。。。今天2024年01月15日终于调成功了,以下是代码,能取到预支付订单号就行了。。
2024年7月25日 再测试,好像之前的不行,还得再加上一步,还需要二次签名。。。
/// <summary>
/// 微信支付-微信小程序
/// </summary>
/// <returns></returns>
[HttpGet("Wxpay_app")]
public async Task<ApiResult> Wxpay_app(string wxappopenid)
{
try
{
if (string.IsNullOrEmpty(wxappopenid))
{
throw new Exception("wxappopenid is null.");
}
//微信支付V2-统一下单文档 https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1
//1.准备提交数据
Hashtable ht = new Hashtable();
ht.Add("appid", "wxd64fd8b6ce123486");
ht.Add("mch_id", "1628000000");
ht.Add("nonce_str", Guid.NewGuid().ToString().Replace("-", ""));
ht.Add("sign_type", "MD5");
ht.Add("body", "腾讯充值中心-QQ会员充值");
ht.Add("out_trade_no", DateTime.Now.ToString("yyyyMMddHHmmss") + Guid.NewGuid().ToString().Substring(0, 4));
ht.Add("total_fee", 1);
ht.Add("spbill_create_ip", HttpContext.UserHostAddress().ToString());
ht.Add("notify_url", "https://bbb.sss.net/api/wx/notify");
ht.Add("trade_type", "JSAPI");
ht.Add("openid", wxappopenid);
//2.签名: 排序、拼接、MD5, 把生成的签名加入到提交数据的sign中
string pinjie = "";
string key = "keykeykey0123456789jccy";
SortedDictionary<string, string> sortedDictionary = new SortedDictionary<string, string>();
foreach (DictionaryEntry entry in ht)
{
sortedDictionary.Add(entry.Key.ToString(), entry.Value.ToString());
}
foreach (KeyValuePair<string, string> pair in sortedDictionary)
{
if (string.IsNullOrEmpty(pair.Value)) { continue; }
pinjie += $"{pair.Key}={pair.Value}&";
}
pinjie += "key=" + key;
_logger.LogInformation("拼接好的串:\r\n" + pinjie + "\r\n");
string sign = Tool.MD5Hash(pinjie).ToUpper();
ht.Add("sign", sign);
//3.把提交的数据转为XML
XmlDocument xmlDoc = new XmlDocument();
XmlElement rootElement = xmlDoc.CreateElement("xml");
xmlDoc.AppendChild(rootElement);
foreach (DictionaryEntry entry in ht)
{
XmlElement element = xmlDoc.CreateElement(entry.Key.ToString());
element.InnerText = entry.Value.ToString();
rootElement.AppendChild(element);
}
string postdata = xmlDoc.OuterXml;
_logger.LogInformation("提交的XML:\r\n" + postdata + "\r\n");
//4.把XML数据POST提交到微信支付V2的接口地址,得到返回的预支付订单号
string aaa = "";
string package = "prepay_id=";
using (var client = new HttpClient())
{
var content = new StringContent(postdata, Encoding.UTF8, "application/xml");
var response = await client.PostAsync("https://api.mch.weixin.qq.com/pay/unifiedorder", content);
if (response.IsSuccessStatusCode)
{
aaa = await response.Content.ReadAsStringAsync();
_logger.LogInformation("远程返回:\r\n" + aaa + "\r\n");
if (aaa.Contains("FAIL")) {
//失败 <result_code><![CDATA[FAIL]]></result_code>
throw new Exception(aaa);
}
XDocument xdoc = XDocument.Parse(aaa);
var ad = from a in xdoc.Descendants("xml")
select new
{
return_code = a.Element("return_code").Value,
return_msg = a.Element("return_msg").Value,
appid = a.Element("appid").Value,
mch_id = a.Element("mch_id").Value,
nonce_str = a.Element("nonce_str").Value,
sign = a.Element("sign").Value,
result_code = a.Element("result_code").Value,
prepay_id = a.Element("prepay_id").Value,
trade_type = a.Element("trade_type").Value,
};
var a1 = ad.FirstOrDefault();
if (a1.result_code == "SUCCESS" && a1.return_code == "SUCCESS")
{
package += a1.prepay_id;
}
else
{
throw new Exception(a1.return_msg);
}
}
else
{
throw new Exception($"StatusCode: {response.StatusCode}");
}
}
//5.小程序调起微信支付还需要再进行二次签名 https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_7&index=5
Hashtable ht_return = new Hashtable();
ht_return.Add("appId", ht["appid"]);
ht_return.Add("timeStamp", DateTimeOffset.UtcNow.ToUnixTimeSeconds());
ht_return.Add("nonceStr", ht["nonce_str"]);
ht_return.Add("package", package);
ht_return.Add("signType", ht["sign_type"]);
string sign2 = Tool.MD5Hash($"appId={ht_return["appId"]}&nonceStr={ht_return["nonceStr"]}&package={ht_return["package"]}&signType={ht_return["signType"]}&timeStamp={ht_return["timeStamp"]}&key={key}").ToUpper();
ht_return.Add("paySign", sign2);
return new ApiResult()
{
code = 0,
msg = aaa,
data = ht_return,
};
}
catch (Exception ex)
{
return new ApiResult() { code = 1, msg = "出错:" + ex.Message };
}
}
注意MD5加密那里得用utf8,原来是ascii的总是签名错误
/// <summary>
/// netcore下的实现MD5加密
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static string MD5Hash(string input)
{
using (var md5 = MD5.Create())
{
var result = md5.ComputeHash(Encoding.UTF8.GetBytes(input)); //用Encoding.ASCII的话在微信支付V2那里的签名不匹配
var strResult = BitConverter.ToString(result);
return strResult.Replace("-", "");
}
}