微信小程式支付服務端.net core實現,簡單直接
阿新 • • 發佈:2020-08-17
做小程式的支付時,在翻閱了大量的別人分享的程式碼後,感覺寫的簡直就是一堆垃圾,不敢苟同,要是程式碼都那麼寫,維護性簡直了,於是才有了這篇文章。
首先流程是很清楚的,就是先統一下單拼一個xml,然後把有值的引數排序後做計算一個簽名,把簽名也寫到xml中,提交給微信,返回發起支付需要的引數,緊接著進行二次簽名,將結果返回給小程式,小程式去調微信api發起支付
1,將需要拼接程xml的引數都寫到一個類裡邊
[Serializable] [XmlRoot(ElementName = "xml", Namespace = "",IsNullable =true,DataType ="")]public class WxUnifiedOrder { [XmlElement(ElementName = "appid")] public string AppId { get; set; } [XmlElement(ElementName = "mch_id")] public string Mch_Id { get; set; } [XmlElement(ElementName = "device_info")] public string Device_Info { get; set; } [XmlElement(ElementName = "nonce_str")] public string Nonce_Str { get; set; } [XmlElement(ElementName = "sign")] public string Sign { get; set; } /// <summary> /// 商品描述 /// </summary> [XmlElement(ElementName = "body")] publicstring Body { get; set; } /// <summary> /// 商戶訂單號 /// </summary> [XmlElement(ElementName = "out_trade_no")] public string Out_Trade_No { get; set; } /// <summary> /// 訂單金額 /// </summary> [XmlElement(ElementName = "total_fee")] public int Total_Fee { get; set; } /// <summary> /// 終端IP /// </summary> [XmlElement(ElementName = "spbill_create_ip")] public string Spbill_Create_Ip { get; set; } /// <summary> /// 通知地址 /// </summary> [XmlElement(ElementName = "notify_url")] public string Notify_Url { get; set; } /// <summary> /// 交易型別 /// </summary> [XmlElement(ElementName = "trade_type")] public string Trade_Type { get; set; } [XmlElement(ElementName = "openid")] public string OpenId { get; set; }
加上特性,標明最終生成xml的文件結構。
2,寫個xml簡單的操作類,就是個序列化和反序列化的過程
public static class XMLOption { public static string ToXml<T>(this T obj, Encoding encoding) { string result = string.Empty; try { using (MemoryStream memoryStream = new MemoryStream()) { XmlSerializer xmlSerializer = new XmlSerializer(obj.GetType()); //序列化物件 XmlSerializerNamespaces namespaes = new XmlSerializerNamespaces(); namespaes.Add("", ""); XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, encoding); xmlTextWriter.Formatting = System.Xml.Formatting.None; xmlSerializer.Serialize(xmlTextWriter, obj, namespaes); xmlTextWriter.Flush(); xmlTextWriter.Close(); result = encoding.GetString(memoryStream.ToArray()); } } catch (Exception ex) { } return result; } public static T ToXmlObject<T>(this string str, Encoding encoding) { try { using (MemoryStream memoryStream = new MemoryStream()) { var buffer = encoding.GetBytes(str); memoryStream.Write(buffer, 0, buffer.Length); memoryStream.Position = 0; XmlSerializer xmlSerializer = new XmlSerializer(typeof(T)); var result = xmlSerializer.Deserialize(memoryStream); return (T)result; } } catch (Exception ex) { return default; } } }View Code
3.一個模擬post請求的公用方法
/// <summary> /// 模擬POST提交 /// </summary> /// <param name="url">請求地址</param> /// <param name="xmlParam">xml引數</param> /// <returns>返回結果</returns> public string PostHttpResponse(string url, string xmlParam) { HttpWebRequest myHttpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url); myHttpWebRequest.Method = "POST"; myHttpWebRequest.ContentType = "application/x-www-form-urlencoded;charset=utf-8"; // Encode the data byte[] encodedBytes = Encoding.UTF8.GetBytes(xmlParam); myHttpWebRequest.ContentLength = encodedBytes.Length; // Write encoded data into request stream Stream requestStream = myHttpWebRequest.GetRequestStream(); requestStream.Write(encodedBytes, 0, encodedBytes.Length); requestStream.Close(); HttpWebResponse result; try { result = (HttpWebResponse)myHttpWebRequest.GetResponse(); } catch { return string.Empty; } if (result.StatusCode == HttpStatusCode.OK) { using (Stream mystream = result.GetResponseStream()) { using (StreamReader reader = new StreamReader(mystream)) { return reader.ReadToEnd(); } } } return null; }View Code
4.再來一個擴充套件方法,計算string字串的md5值
/// <summary> /// 對字串進行MD5加密 /// </summary> /// <param name="strIN">需要加密的字串</param> /// <returns>密文</returns> public static string MD5(this string source) { if (source == null) { return null; } using (MD5 md5 = System.Security.Cryptography.MD5.Create()) { byte[] result = md5.ComputeHash(Encoding.UTF8.GetBytes(source)); string strResult = BitConverter.ToString(result); return strResult.Replace("-", ""); } }View Code
5.填充需要提交的資訊,並計算簽名
var wxUnifiedOrder = new WxUnifiedOrder() { AppId = wxsetting.Appid, Body = product.Name, Device_Info = "WEB", Mch_Id = wxsetting.Mch_id, Nonce_Str = Guid.NewGuid().ToString().Replace("-", "").ToUpper(), Notify_Url = _configuration["WechatPaied:Notify_Url"], Out_Trade_No = orderinfo.OrderCode, Sign = null, Spbill_Create_Ip = _configuration["WechatPaied:Spbill_Create_Ip"], Total_Fee = 1,// Convert.ToInt32(orderinfo.TotalPrice * 100) Trade_Type = "JSAPI", OpenId = uinfo.OpenId }; var type = wxUnifiedOrder.GetType(); SortedDictionary<string, string> param = new SortedDictionary<string, string>(); foreach (var item in type.GetProperties()) { if (item.GetValue(wxUnifiedOrder) != null && item.Name != "Sign") { param.Add(item.Name.ToLower(), item.GetValue(wxUnifiedOrder).ToString()); } } List<string> lstparams = new List<string>(); foreach (var item in param) { lstparams.Add(string.Concat(item.Key, "=", item.Value)); } lstparams.Add(string.Concat("key", "=", _configuration["WechatPaied:Api_Key"])); string param_Sign = string.Join("&", lstparams); wxUnifiedOrder.Sign =param_Sign.MD5().ToUpper();//計算簽名
這裡的SortedDictionary提供的就是一個排序後的引數列表,緊接著把他們按照排列好的順序,拼起來,最後把key加上,呼叫.MD5這個擴充套件方法計算簽名,把model填充起來
6.模擬請求一下微信提供的介面,執行統一下單,拿到返回值
string xmldoc = wxUnifiedOrder.ToXml(Encoding.UTF8); var result = PostHttpResponse("https://api.mch.weixin.qq.com/pay/unifiedorder", xmldoc); var resultData = result.ToXmlObject<WxUnifiedOrderResponse>(Encoding.UTF8);
PostHttpResponse 方法上文已提供 .ToXml .ToXmlObject上文也有提供,就是操作xml序列化的那兩
6.1:WxUnifiedOrderResponse model內容:
[System.SerializableAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] [System.Xml.Serialization.XmlRootAttribute(ElementName = "xml", Namespace = "", IsNullable = false)] public class WxUnifiedOrderResponse { /// <summary> /// 返回狀態碼 /// </summary> [XmlElement(ElementName = "return_code")] public string Return_Code { get; set; } /// <summary> /// 返回資訊 /// </summary> [XmlElement(ElementName = "return_msg")] public string Return_Msg { get; set; } /// <summary> /// 小程式id /// </summary> [XmlElement(ElementName = "appid")] public string Appid { get; set; } /// <summary> /// 商戶號 /// </summary> [XmlElement(ElementName = "mch_id")] public string Mch_Id{get;set;} /// <summary> /// 隨機字串 /// </summary> [XmlElement(ElementName = "nonce_str")] public string Nonce_Str { get; set; } /// <summary> /// /// </summary> [XmlElement(ElementName = "openid")] public string Openid { get; set; } /// <summary> /// 微信返回的簽名 /// </summary> [XmlElement(ElementName = "sign")] public string Sign { get; set; } /// <summary> /// 業務結果 /// </summary> [XmlElement(ElementName = "result_code")] public string Result_Code { get; set; } /// <summary> /// 預支付交易回話標識 /// </summary> [XmlElement(ElementName = "prepay_id")] public string Prepay_Id { get; set; } /// <summary> /// 交易型別 /// </summary> [XmlElement(ElementName = "trade_type")] public string Trade_Type { get; set; } }View Code
7,再次簽名
TimeSpan ts = DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0, 0); var wxPaidParams = new WxPaidParams() { appId = unifiedOrder.Data.Appid, nonceStr = unifiedOrder.Data.Nonce_Str, package = string.Concat("prepay_id=", unifiedOrder.Data.Prepay_Id), signType = "MD5", timeStamp = Convert.ToInt64(ts.TotalSeconds).ToString() }; var type = wxPaidParams.GetType(); SortedDictionary<string, string> param = new SortedDictionary<string, string>(); foreach (var item in type.GetProperties()) { if (item.GetValue(wxPaidParams) != null && item.Name != "paySign") { param.Add(item.Name, item.GetValue(wxPaidParams).ToString()); } } List<string> lstparams = new List<string>(); foreach (var item in param) { lstparams.Add(string.Concat(item.Key, "=", item.Value)); } lstparams.Add(string.Concat("key", "=", _configuration["WechatPaied:Api_Key"])); string param_paySign = string.Join("&", lstparams); wxPaidParams.paySign = param_paySign.MD5().ToUpper();
7.1WxPaidParams
public class WxPaidParams { /// <summary> /// appid /// </summary> public string appId { get; set; } /// <summary> /// 時間戳 /// </summary> public string timeStamp { get; set; } /// <summary> /// 隨機串 /// </summary> public string nonceStr { get; set; } /// <summary> /// 資料包 /// </summary> public string package { get; set; } /// <summary> /// 簽名方式 /// </summary> public string signType { get; set; } /// <summary> /// 簽名 /// </summary> public string paySign { get; set; } }View Code
一毛一樣,的道理,主邏輯寫下來不到100行程式碼,將來統一下單地方的引數有變化,僅僅需要增加欄位,賦值就可以,其他都不動,
再把下邊那坨加密的東西再稍微封裝一下,用到生產環境妥妥的。