Json.Net学习笔记(十三) 缩小序列化Json的大小

当序列化.Net对象为Json对象时经常会遇到的一个问题是:最终的Json包含大量多余的属性和属性值。这个问题在返回Json到客户端时显得特别重要。Json越大意味着需要更大的带宽,使网速变得更慢。

为了解决多余的Json这个问题,Json.Net有一系列内置的选项可以进行调整。

->JsonIgnoreAttribute and DataMemberAttribute

默认情况下,在Json创建的时候Json.Net会包含所有类级别的public属性和字段。添加JsonIgnoreAttribute到属性上,告诉序列化器序列化时跳过它。

 public class Car
    {
        // included in JSON
        public string Model { get; set; }
        public DateTime Year { get; set; }
        public List<string> Features { get; set; }

        // ignored
        [JsonIgnore]
        public DateTime LastModified { get; set; }
    }

如果类有很多属性,你只想序列化它的一小部分,添加JsonIgore到所有其他的属性上会比较冗余,也比较容易出错。有一种用来处理这种情况的方法,添加DataContractAttribute到类上,添加DataMemberAttribute到需要被序列化的属性上。与使用JsonIgnoreAttribute的opt-out序列化相比,opt-in序列化仅仅你标记的属性被需列化。

using System.Runtime.Serialization;

  [DataContract]
    public class Computer
    {
        // included in JSON
        [DataMember]
        public string Name { get; set; }
        [DataMember]
        public decimal SalePrice { get; set; }

        // ignored
        public string Manufacture { get; set; }
        public int StockCount { get; set; }
        public decimal WholeSalePrice { get; set; }
        public DateTime NextShipmentDate { get; set; }
    }

->Formatting

Json序列化时,用可选参数Formatting.Indented生成良好的显示格式,可读性更好。另一方面,Formatting.None会跳过不必要的空格和换行符,让Json的结果更小。生成的显示格式更加紧凑,也许效率更高。

->NullValueHandling

   在序列化器中NullVlaueHandling是可选的。它控制序列化器如何处理值为null的属性。通过设置NullValueHandling.Ignore值,序列化器会跳过值为null的属性。

  public class Movie
    {
        public string Name { get; set; }
        public string Description { get; set; }
        public string Classification { get; set; }
        public string Studio { get; set; }
        public DateTime? ReleaseDate { get; set; }
        public List<string> ReleaseCountries { get; set; }
    }

测试1:

           Movie movie = new Movie();
            movie.Name = "Bad Boys III";
            movie.Description = "It's no Bad Boys";

            string included = JsonConvert.SerializeObject(movie,
              Formatting.Indented,
              new JsonSerializerSettings { });
            Console.WriteLine(included);

输出结果:

{
  "Name": "Bad Boys III",
  "Description": "It's no Bad Boys",
  "Classification": null,
  "Studio": null,
  "ReleaseDate": null,
  "ReleaseCountries": null
}

测试2:

           string ignored = JsonConvert.SerializeObject(movie,
              Formatting.Indented,
              new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
            Console.WriteLine(ignored);

输出结果:

{
  "Name": "Bad Boys III",
  "Description": "It's no Bad Boys"
}

NullValueHandling也可以在单独的属性上用JsonPropertyAttribute进行定制。使用JsonPropertyAttribute时设置的NullValueHandling值会在Json序列化器中为该属性进行重写。

->DefaultValuehandling

   在序列化器中DefaultValuehandling是可选的。它控制序列化器如何处理带有默认值的属性。通过设置DefaultValuehandling.Ignore值,序列化器会跳过带有默认值的属性。对于引用类型为null,对于值类型,如int和DateTime,序列化器将跳过默认未初使化值的值类型。

  Json.Net也允许你通过DefaultValueAttribute自定义默认值,例如:如果一个字符串类型的属性Department在它的默认状态下总是返回一个空字符,但是在你的Json对象中你不想要那个空字符串,你可以在Department上使用空字符串参数标记DefaultValueAttribute,这意味着Department在序列化时不再写入Json中,除非它有非空值。

  public class Invoice
    {
        public string Company { get; set; }
        public decimal Amount { get; set; }

        // false is default value of bool
        public bool Paid { get; set; }
        // null is default value of nullable
        public DateTime? PaidDate { get; set; }

        // customize default values
        [DefaultValue(30)]
        public int FollowUpDays { get; set; }
        [DefaultValue("")]
        public string FollowUpEmailAddress { get; set; }
    }

测试1:

           Invoice invoice = new Invoice
            {
                Company = "Acme Ltd.",
                Amount = 50.0m,
                Paid = false,
                FollowUpDays = 30,
                FollowUpEmailAddress = string.Empty,
                PaidDate = null
            };

            string includedDefaultValue = JsonConvert.SerializeObject(invoice,
              Formatting.Indented,
              new JsonSerializerSettings { });
            Console.WriteLine(includedDefaultValue);

输出结果:

{
  "Company": "Acme Ltd.",
  "Amount": 50.0,
  "Paid": false,
  "PaidDate": null,
  "FollowUpDays": 30,
  "FollowUpEmailAddress": ""
}

测试2:

            string ignoredDefaultValue = JsonConvert.SerializeObject(invoice,
              Formatting.Indented,
              new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.Ignore });
            Console.WriteLine(ignoredDefaultValue);

输出结果:

{
  "Company": "Acme Ltd.",
  "Amount": 50.0,
  "Paid": false//??
}

DefaultValueHandling也可以在单独的属性上用JsonPropertyAttribute进行定制。使用JsonPropertyAttribute时设置的DefaultValueHandling值会在Json序列化器中为该属性进行重写。

->IContractResolver

  为了获得更多的灵活性,IContractResolver接口提供了定制.Net对象序列化为Json的每一个方面,包括在运行时改变序列化的行为。

 public class DynamicContractResolver : DefaultContractResolver
    {
        private readonly char _startingWithChar;
        public DynamicContractResolver(char startingWithChar)
        {
            _startingWithChar = startingWithChar;
        }

        protected override IList<JsonProperty> CreateProperties(JsonObjectContract contract)
        {
            IList<JsonProperty> properties = base.CreateProperties(contract);

            // only serializer properties that start with the specified character
            properties =
              properties.Where(p => p.PropertyName.StartsWith(_startingWithChar.ToString())).ToList();

            return properties;
        }
    }

    public class Book
    {
        public string BookName { get; set; }
        public decimal BookPrice { get; set; }
        public string AuthorName { get; set; }
        public int AuthorAge { get; set; }
        public string AuthorCountry { get; set; }
    }

测试:

           Book book = new Book
            {
                BookName = "The Gathering Storm",
                BookPrice = 16.19m,
                AuthorName = "Brandon Sanderson",
                AuthorAge = 34,
                AuthorCountry = "United States of America"
            };

            string startingWithA = JsonConvert.SerializeObject(book, Formatting.Indented,
              new JsonSerializerSettings { ContractResolver = new DynamicContractResolver('A') });
            Console.WriteLine(startingWithA);
            // {
            //   "AuthorName": "Brandon Sanderson",
            //   "AuthorAge": 34,
            //   "AuthorCountry": "United States of America"
            // }

            string startingWithB = JsonConvert.SerializeObject(book, Formatting.Indented,
              new JsonSerializerSettings { ContractResolver = new DynamicContractResolver('B') });
            Console.WriteLine(startingWithA);
            // {
            //   "BookName": "The Gathering Storm",
            //   "BookPrice": 16.19
            // }

你可能感兴趣的:(.net)