C#校驗(yàn)時(shí)間格式的場(chǎng)景分析
前言:
晚上打算睡覺(jué)的時(shí)候,群里反饋訂單接收失敗,開(kāi)工排查問(wèn)題,日志顯示驗(yàn)簽失敗,發(fā)現(xiàn)一個(gè)蠻有意思的BUG,總算有了一個(gè)寫作的素材
場(chǎng)景描述
本次的場(chǎng)景屬于比較常見(jiàn)的收單API,對(duì)第三方的訂單進(jìn)行簽名驗(yàn)證,然后持久化到數(shù)據(jù)庫(kù),簽名規(guī)則大致是將參數(shù)key按照升序排序,然后根據(jù)key=value&進(jìn)行字符串拼接,最后加上秘鑰,按照指定的加密方式生成簽名
前戲一
設(shè)計(jì)之初,肯定是怎么簡(jiǎn)單怎么來(lái),粗略代碼如下
[HttpPost] public async Task<IActionResult> TestSendOrder([FromBody] ReceiveOrderRequest request) { var secret_key = _options.Value.SecretKey; var url = _options.Value.Host; //1.將模型轉(zhuǎn)成json格式字符串 var param = JsonConvert.SerializeObject(request); //2.將json格式字符串,序列化成有序字典 SortedDictionary<string, string> dict = JsonConvert.DeserializeObject<SortedDictionary<string, string>>(param); //3.循環(huán)字典,按規(guī)則拼接成待加密的明文字符串 var data = ""; foreach (var item in dict) { if (item.Key == "sign") continue; data += $"{item.Key}={item.Value}&"; } data += $"secret_key={secret_key}"; //4.生成簽名 var sign = EncryptHelper.SHA1Encryption(data); request.sign = sign; //5.模擬訂單推送 var res = await _httpClientHelper.PostData(url, JsonConvert.SerializeObject(request)); return Ok(res); }
不出意外,肯定是要出意外的,聯(lián)調(diào)的時(shí)候,發(fā)現(xiàn)與第三方待加密的明文字符串不一致,問(wèn)題出在JsonConvert序列化上,這里有兩個(gè)問(wèn)題
1. DateTime格式不一致 如: DateTime dt = "2022-07-30 12:26:56" 序列化后 dt=2022-07-30T12:26:56 2. decimal小數(shù)點(diǎn)后自動(dòng)補(bǔ)0 如: decimal price = 10 序列化后 price=10.0
針對(duì)第一個(gè)問(wèn)題,很好解決,我們?cè)谛蛄谢臅r(shí)候,指定DateTime的格式即可
var iso = new IsoDateTimeConverter(); iso.DateTimeFormat = "yyyy-MM-dd HH:mm:ss"; var param = JsonConvert.SerializeObject(request, iso);
針對(duì)第二個(gè)問(wèn)題,處理起來(lái)就比較麻煩了,要重寫底層的一些東西(主要是我不會(huì)),這不符合"簡(jiǎn)單"的定義,得換個(gè)方案
前戲二
通過(guò)反射遍歷對(duì)象,然后將屬性名稱與值,丟到有序字典里面,這里我寫了個(gè)方法來(lái)判斷值是否為時(shí)間,如果是時(shí)間類型,則格式化,代碼如下
public string GetFmortDateTime(string strDate) { DateTime dt; if (DateTime.TryParse(strDate, out dt)) { return dt.ToString("yyyy-MM-dd HH:mm:ss"); } else { return strDate; } }
不出意外,肯定是要出意外的,不然也不會(huì)有這個(gè)素材去水一篇博客了
正戲
有個(gè)字段的值是9.9,結(jié)果被序列化成了 2022-09-09 00:00:00,吃了一驚,看來(lái)是把這個(gè)數(shù)字格式化成月份日份了,真有意思,又GET到一個(gè)新姿勢(shì),發(fā)現(xiàn)問(wèn)題解決問(wèn)題就簡(jiǎn)單多了,因?yàn)槎x了數(shù)據(jù)模型,我們直接在反射的時(shí)候,獲取該值的類型做判斷即可
public static async Task<bool> CheckSign(dynamic request, string secret) { SortedDictionary<string, string> dict = new SortedDictionary<string, string>(); foreach (PropertyInfo p in request.GetType().GetProperties()) { var value = p.GetValue(request); if (value == null) { dict[p.Name] = ""; } else { var valueType = value.GetType(); if (valueType.Name == "DateTime") { dict[p.Name] = Convert.ToDateTime(value).ToString("yyyy-MM-dd HH:mm:ss"); } else { dict[p.Name] = value.ToString(); } } } var sign = dict["sign"]; dict.Remove("sign"); var data = ""; foreach (var item in dict) { data += $"{item.Key}={item.Value}&"; } data += $"secret_key={secret}"; var new_sign = EncryptHelper.SHA1Encryption(data); return new_sign.ToLower() == sign.ToLower(); }
尾戲
看到這里,可能就有小伙伴有話要說(shuō)了,你這定義了一個(gè)模型,還要通過(guò)循環(huán)兩次,才能生成待加密的明文字符串,不符合"簡(jiǎn)單",干脆直接用個(gè)有序字典去接收參數(shù)好了,這樣只用循環(huán)一次
秒啊,秒啊,秒啊,妙蛙種子都沒(méi)有你秒,這種做法不是不行,但是后面維護(hù)的人估計(jì)要抓狂了,按照規(guī)約,我們是不推薦這么干的,這次就破例這么干一次,拋出另一個(gè)問(wèn)題,一個(gè)字符串,如何判斷它是一個(gè)我們約定的時(shí)間格式,很顯然9.9并不是約定的時(shí)間格式
這里推薦 DateTime.ParseExact方法,可以根據(jù)我們自定義的方式,來(lái)格式化時(shí)間,舒坦了...
public static string GetFmortDateTime(string strDate) { string[] format = { "yyyy-MM-ddTHH:mm:ss" }; DateTime dt; if (DateTime.TryParseExact(strDate,format,CultureInfo.InvariantCulture,DateTimeStyles.None,out dt)) { return dt.ToString("yyyy-MM-dd HH:mm:ss"); } else { return strDate; } }
到此這篇關(guān)于C#里如何簡(jiǎn)單的校驗(yàn)時(shí)間格式的文章就介紹到這了,更多相關(guān)C#校驗(yàn)時(shí)間格式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
c#動(dòng)態(tài)編譯執(zhí)行對(duì)象方法示例 運(yùn)用映射機(jī)制創(chuàng)建對(duì)象
本示例核心技術(shù)是運(yùn)用.NET動(dòng)態(tài)編譯技術(shù)+.NET映射技術(shù),把一個(gè)代碼塊中的代碼,動(dòng)態(tài)編譯成程序集后,在運(yùn)用映射機(jī)制,創(chuàng)建對(duì)象示例,調(diào)用對(duì)象方法2014-01-01C#實(shí)現(xiàn)SMTP服務(wù)發(fā)送郵件的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何利用C#實(shí)現(xiàn)SMTP服務(wù)發(fā)送郵件的功能,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C#有一定的幫助,感興趣的小伙伴可以跟隨小編一起了解一下2022-12-12C#環(huán)形緩沖區(qū)(隊(duì)列)完全實(shí)現(xiàn)
這篇文章主要為大家詳細(xì)介紹了C#環(huán)形緩沖區(qū)(隊(duì)列)完全實(shí)現(xiàn)代碼,感興趣的小伙伴們可以參考一下2016-07-07基于WPF實(shí)現(xiàn)3D畫(huà)廊動(dòng)畫(huà)效果的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何基于WPF實(shí)現(xiàn)簡(jiǎn)單的3D畫(huà)廊動(dòng)畫(huà)效果,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-02-02C#實(shí)現(xiàn)公式計(jì)算驗(yàn)證碼的示例詳解
現(xiàn)在很多的平臺(tái)已經(jīng)不使用普通的數(shù)字、字母等驗(yàn)證碼了,取而代之的是拼圖類、選圖類、旋轉(zhuǎn)類或者計(jì)算類的驗(yàn)證碼。本文將利用C#實(shí)現(xiàn)一個(gè)公式計(jì)算驗(yàn)證碼,感興趣的可以了解一下2022-10-10簡(jiǎn)介Winform中創(chuàng)建用戶控件
用戶控件可以讓開(kāi)發(fā)人員對(duì)VS控件進(jìn)行組裝。下面我們來(lái)創(chuàng)建一個(gè)按鈕的用戶控件我們可以給它添加屬性,并且添加相應(yīng)鼠標(biāo)移入、移出事件。2013-03-03