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


0  緣由

  筆者最近在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

  筆者將分別對這三種進行序列化與反序列化復雜對象,使用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; }
    }
}
View Code

  筆者這里先貼出序列化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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM