Net中JSON序列化和反序列化處理(日期時間特殊處理)
筆者最近在web api端使用Json.Net進行序列化處理,而在調用端使用DataContractSerializer進行反序列化,遇到日期時間處理反序列化不成功【 備注 :筆者使用Net Framework 4.0】。究其原因,Json.Net默認的日期輸出是ISO標準時間,而微軟默認的輸出與解析日期格式是/Date(1242357713797+0800)/。可以看出我們只需將ISO的標準時間轉換成微軟能夠識別日期時間格式即可。最后筆者就想重新對比下Net中Json序列化和反序列化的三種處理方式,以及性能。
1 介紹
Net中Json序列化反序列化一般常用的有三種:
- JavaScriptSerializer[位于程序集:System.Web.Extension.dll,命令空間:System.Web.Script.Serialization]
- DataContractSerializer[位于程序集:System.Runtime.Serialization.dll,命名空間:System.Runtime.Serialization.Json]
- JsonConvert[位于程序集:Newtonsoft.Json.dll,命名空間:Newtonsoft.Json],外部引用庫,可通過Nuget進行獲取Json.Net </ul>
筆者將分別對這三種進行序列化與反序列化復雜對象,使用Stopwatch進行監測其運行的時間。對比Stopwatch的運行時間,從而得出性能較佳的序列化Json的實現
2 三者對比
新建一個Mvc3.0 項目命名為JsonConvertSample,使用Nuget引入Json.Net(在程序包管理器控制臺鍵入:Install-Package Newtonsoft.Json),準備一個復雜類User,以及對比類JsonCompare。主要代碼如下:
//===================================================== //Copyright (C) www.cnblogs.com/luge //All rights reserved //文件名: JsonCompare //創建時間: 2015-06-21 //當前登錄用戶名: 鹵鴿 //描述: //====================================================== namespace JsonConvertSample.Models { public class JsonCompare { public double DataContractSerializeTime { get; set; } public string DcsString { get; set; } public double JavascriptSerializeTime { get; set; } public string jsString { get; set; } public double JsonNetTime { get; set; } public string jnString { get; set; } public int Capacity { get; set; } } } namespace JsonConvertSample.Models { public class User { public int UserID { get; set; } public string UserName { get; set; } public decimal Saraly { get; set; } public Address Location { get; set; } public List<School> Schools { get; set; } public DateTime BirthDate { get; set; } } public class Address { public string Province { get; set; } public string City { get; set; } } public class School { public string SchoolName { get; set; } public string SchoolDesc { get; set; } } }
筆者這里先貼出序列化Json三種不同的泛型實現(詳細可下載源碼查看)
#region DataContractJsonSerializer /// <summary> /// 序列化json字符串 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="obj"></param> /// <param name="datetimePattern"> 替換Json的Date字符串 </param> /// <returns></returns> public static string SerializeByContract<T>(T obj, string datetimePattern = null) where T : class { string jsonString = string.Empty; if (obj == null) return jsonString; var ser = new DataContractJsonSerializer(typeof(T)); using (var ms = new MemoryStream()) { ser.WriteObject(ms, obj); jsonString = Encoding.UTF8.GetString(ms.ToArray()); } if (!string.IsNullOrEmpty(datetimePattern)) { MatchEvaluator matchEvaluator = new MatchEvaluator(ConvertJsonDateToDateString); Regex reg = new Regex(datetimePattern); jsonString = reg.Replace(jsonString, matchEvaluator); } return jsonString; } /// <summary> /// json反序列化成對象 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="jsonString"></param> /// <param name="datetimePattern">匹配時間的正則表達式</param> /// <returns></returns> public static T DeserializeByContract<T>(string jsonString, string datetimePattern = null) where T : class { if (string.IsNullOrEmpty(jsonString)) { return default(T); } if (!string.IsNullOrEmpty(datetimePattern)) { MatchEvaluator matchEvaluator = new MatchEvaluator(ConvertDateStringToJsonDate); var reg = new Regex(datetimePattern); jsonString = reg.Replace(jsonString, matchEvaluator); } var ser = new DataContractJsonSerializer(typeof(T)); var jsonByteArr = Encoding.UTF8.GetBytes(jsonString); using (var ms = new MemoryStream(jsonByteArr)) { object obj = ser.ReadObject(ms); return obj as T; } } #endregion #region JavaScriptSerializer public static string SerializeByJavaScript<T>(T obj) where T : class { var jsonString = string.Empty; if (obj == null) { return jsonString; } JavaScriptSerializer js = new JavaScriptSerializer(); //<!--進行序列化或反序列化時出錯。字符串的長度超過了為 maxJsonLength 屬性設置的值--> js.MaxJsonLength = int.MaxValue; jsonString = js.Serialize(obj); return jsonString; } public static T DeserializeByJavaScript<T>(string jsonString) where T : class { T obj; if (string.IsNullOrEmpty(jsonString)) { obj = null; return obj; } JavaScriptSerializer js = new JavaScriptSerializer(); js.MaxJsonLength = int.MaxValue; obj = js.Deserialize<T>(jsonString); return obj; } #endregion #region Json.Net public static string SerializeByJsonNet<T>(T obj) where T : class { var jsonString = string.Empty; if (obj == null) return jsonString; jsonString = JsonConvert.SerializeObject(obj); return jsonString; } public static T DeserializeByJsonNet<T>(string jsonString) where T : class { T obj = null; if (string.IsNullOrEmpty(jsonString)) { return obj; } obj = JsonConvert.DeserializeObject<T>(jsonString); return obj; } #endregion
測試代碼局部代碼(詳細可下載源碼查看):
Stopwatch sw = new Stopwatch(); sw.Start(); jsonCompare.DcsString = JsonFormat.SerializeByContract<IList<User>>(list); sw.Stop(); jsonCompare.DataContractSerializeTime = sw.ElapsedTicks;
根據不同方式序列化Json得出的結果
由上面的圖片結果可以得出結論: Json.Net 優于 DataContractSerialize, DataContractSerialize 優于 JavaScriptSerialize,而且Json.Net甩JavaScriptSerialize幾大街。
4、日期時間的處理
本文篇頭對筆者遇到的問題已經提出處理方案。針對DataContractSerializer進行反序列化日期時間(由json.net序列化)的處理,如果在Net4.0中,正則表達式匹配對日期類型統一替換即可實現之;當然在Net4.5解決方法就更加簡單,只需如下設置,即可完成反序列化json。核心處理代碼如下:
#if Net45 DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T), new DataContractJsonSerializerSettings() { DateTimeFormat = new DateTimeFormat("yyyy-MM-dd'T'HH:mm:ss") }); #endif #if Net40 private static string ConvertDateStringToJsonDate(Match m) { string result = string.Empty; DateTime dt = DateTime.Parse(m.Groups[0].Value); dt = dt.ToUniversalTime(); TimeSpan ts = dt - DateTime.Parse("1970-01-01"); result = string.Format("\\/Date({0}+0800)\\/",ts.TotalMilliseconds.ToString("f0")); return result; } string datetimePattern="(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)(?:([\+-])(\d{2})\:(\d{2}))?Z?"; MatchEvaluator matchEvaluator = new MatchEvaluator(ConvertDateStringToJsonDate); var reg = new Regex(datetimePattern); jsonString = reg.Replace(jsonString, matchEvaluator); #endif
5、總結與源碼
- JavaScriptSerialize如果序列化對象過大時將會出現“進行序列化或反序列化時出錯。字符串的長度超過了為 maxJsonLength 屬性設置的值”,只需設置MaxJsonLength=int.MaxValue
- 源碼(如果覺得不錯請點贊下,有誤的話請指出,鹵鴿在此感謝)
參考:
http://blog.csdn.net/cncdns/article/details/6164389