最近要做一个微信小程序支付的功能 在网上找了一下 .net Core做微信支付的博客 和 demo 几乎没有
自己研究了好几天 参考了 很多 大牛的博客 勉强做出来了 因为参数都没有 比如 opid 小程序域名 所以只是简单的测了一下 模拟了微信支付的回调请求 后续等项目上线 会回来填坑的
第一次看小程序支付的api文档 看得我一脸懵逼 现在简单说一下吧 先上一个官方图
![图片[1]-Asp.net Core 微信小程序支付-八度分享](https://www.8dus.com/wp-content/uploads/2021/04/6f09cd9d2040.png)
小程序支付的流程是这样的 首先 用户下单 然后后台生成订单 调用统一支付api(注意这并不是支付 只是算一个预下单 通知下微信 我要掏钱了 你给我几个参数) 然后 统一下单API回返回给你五个参数 把五个参数和签名返回给前端 由前端来下单
然后用户确认支付之后 会有一个微信的异步回调
(此处调用统一下单需要用的opid 在微信登录那一块 不做赘述)
关于统一下单
构造下单参数 — 调用API接口 — 处理返回结果 — 返回给前端
首先 构造统一下单的所需要的参数
![图片[2]-Asp.net Core 微信小程序支付-八度分享](https://www.8dus.com/wp-content/uploads/2021/04/3b4aa3a46860.png)
然后发送Http请求 接收返回的结果
![图片[3]-Asp.net Core 微信小程序支付-八度分享](https://www.8dus.com/wp-content/uploads/2021/04/4a0742709439.png)
然后将五个参数返回给前台。
微信支付回调也是
![图片[4]-Asp.net Core 微信小程序支付-八度分享](https://www.8dus.com/wp-content/uploads/2021/04/04c1d6f783c8.png)
拿到微信返回的支付数据 解析数据 处理业务
这里需要注意 core 的接收方式
![图片[5]-Asp.net Core 微信小程序支付-八度分享](https://www.8dus.com/wp-content/uploads/2021/04/0186be6aa183.png)
ok 这里先总结一下 等到测试完 没问题 回来填坑 并附上完整代码
public class WeChatPayHelper
{
private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
public PayRequesEntity Unifiedorder(string openid, string totalfee, string orderNo)
{
//var PayUrl = AppSetting.Load().WechatPayStrings.FirstOrDefault().UnifiedorderURL;
//获取统一下单参数
var param = GetUnifiedOrderParam(openid, orderNo, totalfee);
_logger.Info(() => "微信支付统一下单 发送参数为 "+param+"");
//统一下单后拿到的xml结果
var payResXML = HttpMethods.Post(AppSetting.Load().WechatPayStrings.FirstOrDefault().UnifiedorderURL, param);
_logger.Info(() => "微信支付统一下单 返回参数为 " + payResXML + "");
var payRes = XDocument.Parse(payResXML);
var root = payRes.Element("xml");
var res = GetPayRequestParam(root);
_logger.Info(() => "微信支付统一下单 参数实体为 " + JsonConvert.SerializeObject(res) + "");
return res;
}
/// <summary>
/// 取统一下单的请求参数
/// </summary>
/// <param name="openid"></param>
/// <returns></returns>
private string GetUnifiedOrderParam(string openid,string orderNo, string totalfee)
{
string appid = AppSetting.Load().WechatStrings.FirstOrDefault().APPID;
string secret = AppSetting.Load().WechatStrings.FirstOrDefault().SECRET;
string mch_id = AppSetting.Load().WechatPayStrings.FirstOrDefault().Mch_ID;
string ip = AppSetting.Load().Configurations.FirstOrDefault().IP;
string PayResulturl = AppSetting.Load().WechatPayStrings.FirstOrDefault().PayResulturl;
string strcode = "益谦文化小程序-微信支付购买";////商品描述交易字段格式根据不同的应用场景按照以下格式:APP——需传入应用市场上的APP名字-实际商品名称,天天爱消除-游戏充值。
byte[] buffer = Encoding.UTF8.GetBytes(strcode);
string body = Encoding.UTF8.GetString(buffer, 0, buffer.Length);
System.Random Random = new System.Random();
var dic = new Dictionary<string, string>
{
{"appid", appid},
{"mch_id", mch_id},
{"nonce_str", GetRandomString(20)/*Random.Next().ToString()*/},
{"body",body},
{"out_trade_no",orderNo},//商户自己的订单号码
{"total_fee",totalfee},
{"spbill_create_ip",ip},//服务器的IP地址
{"notify_url",PayResulturl},//异步通知的地址,不能带参数
{"trade_type","JSAPI" },
{"openid",openid}
};
//加入签名
dic.Add("sign", GetSignString(dic));
var sb = new StringBuilder();
sb.Append("<xml>");
foreach (var d in dic)
{
sb.Append("<" + d.Key + ">" + d.Value + "</" + d.Key + ">");
}
sb.Append("</xml>");
return sb.ToString();
}
/// <summary>
/// 获取返回给小程序的支付参数
/// </summary>
/// <param name="root"></param>
/// <param name="appid"></param>
/// <param name="key"></param>
/// <returns></returns>
private PayRequesEntity GetPayRequestParam(XElement root)
{
string appid = AppSetting.Load().WechatStrings.FirstOrDefault().APPID;
//当return_code 和result_code都为SUCCESS时才有我们要的prepay_id
if (root.Element("return_code").Value == "SUCCESS" && root.Element("result_code").Value == "SUCCESS")
{
var res = new Dictionary<string, string>
{
{"appId", appid},
{"timeStamp", Convert.ToInt64((DateTime.Now - new DateTime(1970, 1, 1)).TotalSeconds).ToString()},
{"nonceStr", GetRandomString(20)},
{"package", "prepay_id=" + root.Element("prepay_id").Value},
{"signType", "MD5"}
};
//在服务器上签名
res.Add("paySign", GetSignString(res));
var payEntity = new PayRequesEntity
{
package = res["package"],
nonceStr = res["nonceStr"],
paySign = res["paySign"],
signType = res["signType"],
timeStamp = res["timeStamp"]
};
return payEntity;
}
return new PayRequesEntity();
}
/// <summary>
/// 从字符串里随机得到,规定个数的字符串.
/// </summary>
/// <param name="allChar"></param>
/// <param name="CodeCount"></param>
/// <returns></returns>
private static string GetRandomString(int CodeCount)
{
string allChar = "1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,i,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z";
string[] allCharArray = allChar.Split(',');
string RandomCode = "";
int temp = -1;
Random rand = new Random();
for (int i = 0; i < CodeCount; i++)
{
if (temp != -1)
{
rand = new Random(temp * i * ((int)DateTime.Now.Ticks));
}
int t = rand.Next(allCharArray.Length - 1);
while (temp == t)
{
t = rand.Next(allCharArray.Length - 1);
}
temp = t;
RandomCode += allCharArray[t];
}
return RandomCode;
}
private string GetSignString(Dictionary<string, string> dic)
{
string key = AppSetting.Load().WechatPayStrings.FirstOrDefault().WxPayKey;//商户平台 API安全里面设置的KEY 32位长度
dic = dic.OrderBy(d => d.Key).ToDictionary(d => d.Key, d => d.Value);//排序
//连接字段
var sign = dic.Aggregate("", (current, d) => current + (d.Key + "=" + d.Value + "&"));
sign += "key=" + key;
System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create();
sign = BitConverter.ToString(md5.ComputeHash(Encoding.UTF8.GetBytes(sign))).Replace("-", null);
return sign;
}
private static Object PostUnifiedOrder(string payUrl, string para)
{
string result = string.Empty;
try
{
HttpClient client = new HttpClient();
HttpContent httpContent = new StringContent(para);
httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
httpContent.Headers.ContentType.CharSet = "utf-8";
HttpResponseMessage hrm = client.PostAsync(payUrl, httpContent).Result;
return hrm;
}
catch (Exception e)
{
result = e.Message;
}
return result;
}
}
public class PayRequesEntity
{
/// <summary>
/// 时间戳从1970年1月1日00:00:00至今的秒数,即当前的时间
/// </summary>
public string timeStamp { get; set; }
/// <summary>
/// 随机字符串,长度为32个字符以下。
/// </summary>
public string nonceStr { get; set; }
/// <summary>
/// 统一下单接口返回的 prepay_id 参数值
/// </summary>
public string package { get; set; }
/// <summary>
/// 签名算法
/// </summary>
public string signType { get; set; }
/// <summary>
/// 签名
/// </summary>
public string paySign { get; set; }
}
附: HttpMethods 操作
/// <summary>
/// Http方法
/// </summary>
public class HttpMethods
{
/// <summary>
/// 创建HttpClient
/// </summary>
/// <returns></returns>
public static HttpClient CreateHttpClient(string url, IDictionary<string, string> cookies = null)
{
HttpClient httpclient;
HttpClientHandler handler = new HttpClientHandler();
var uri = new Uri(url);
if (cookies != null)
{
foreach (var key in cookies.Keys)
{
string one = key + "=" + cookies[key];
handler.CookieContainer.SetCookies(uri, one);
}
}
//如果是发送HTTPS请求
if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
{
ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
httpclient = new HttpClient(handler);
}
else
{
httpclient = new HttpClient(handler);
}
return httpclient;
}
#region 同步请求
/// <summary>
/// post 请求
/// </summary>
/// <param name="url">请求地址</param>
/// <param name="jsonData">请求参数</param>
/// <returns></returns>
public static string Post(string url, string jsonData)
{
HttpClient httpClient = CreateHttpClient(url);
var postData = new StringContent(jsonData);
postData.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
Task<string> result = httpClient.PostAsync(url, postData).Result.Content.ReadAsStringAsync();
return result.Result;
}
/// <summary>
/// post 请求
/// </summary>
/// <param name="url">请求地址</param>
/// <param name="req">请求参数</param>
/// <returns></returns>
public static string Post(string url, byte[] req)
{
HttpClient httpClient = CreateHttpClient(url);
var postData = new ByteArrayContent(req);
Task<string> result = httpClient.PostAsync(url, postData).Result.Content.ReadAsStringAsync();
return result.Result;
}
/// <summary>
/// post 请求
/// </summary>
/// <param name="url">请求地址</param>
/// <param name="pairs">请求参数</param>
/// <returns></returns>
public static string Post(string url, Dictionary<string, string> pairs)
{
HttpClient httpClient = CreateHttpClient(url);
var postData = new FormUrlEncodedContent(pairs);
var result = httpClient.PostAsync(url, postData).Result.Content.ReadAsStringAsync();
return result.Result;
}
/// <summary>
/// get 请求
/// </summary>
/// <param name="url">请求地址</param>
/// <returns></returns>
public static string Get(string url)
{
HttpClient httpClient = CreateHttpClient(url);
Task<string> result = httpClient.GetAsync(url).Result.Content.ReadAsStringAsync();
return result.Result;
}
#endregion
#region 异步请求
/// <summary>
/// post 请求
/// </summary>
/// <param name="url">请求地址</param>
/// <param name="jsonData">请求参数</param>
/// <returns></returns>
public static Task<HttpResponseMessage> PostAsync(string url, string jsonData)
{
HttpClient httpClient = CreateHttpClient(url);
var postData = new StringContent(jsonData);
postData.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
var result = httpClient.PostAsync(url, postData);
return result;
}
/// <summary>
/// post 请求
/// </summary>
/// <param name="url">请求地址</param>
/// <param name="req">请求参数</param>
/// <returns></returns>
public static Task<HttpResponseMessage> PostAsync(string url, byte[] req)
{
HttpClient httpClient = CreateHttpClient(url);
var postData = new ByteArrayContent(req);
var result = httpClient.PostAsync(url, postData);
return result;
}
/// <summary>
/// post 请求
/// </summary>
/// <param name="url">请求地址</param>
/// <param name="pairs">请求参数</param>
/// <returns></returns>
public static Task<HttpResponseMessage> PostAsync(string url, Dictionary<string, string> pairs)
{
HttpClient httpClient = CreateHttpClient(url);
var postData = new FormUrlEncodedContent(pairs);
var result = httpClient.PostAsync(url, postData);
return result;
}
/// <summary>
/// get 请求
/// </summary>
/// <param name="url">请求地址</param>
/// <returns></returns>
public static Task<HttpResponseMessage> GetAsync(string url)
{
HttpClient httpClient = CreateHttpClient(url);
var result = httpClient.GetAsync(url);
return result;
}
#endregion
}
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END
