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);
#endif5、總結與源碼
- JavaScriptSerialize如果序列化對象過大時將會出現“進行序列化或反序列化時出錯。字符串的長度超過了為 maxJsonLength 屬性設置的值”,只需設置MaxJsonLength=int.MaxValue
- 源碼(如果覺得不錯請點贊下,有誤的話請指出,鹵鴿在此感謝)
參考:
http://blog.csdn.net/cncdns/article/details/6164389