Net中JSON序列化和反序列化處理(日期時間特殊處理)

jopen 9年前發布 | 35K 次閱讀 JSON 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得出的結果

    Net中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

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!