Net中JSON序列化和反序列化处理(日期时间特殊处理)

jopen 9年前

笔者最近在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; }      }  }

笔者这里先贴出序列化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