Archives

Archives / 2009 / October
  • Breaking Hard Assembly Dependencies

    Smithers: "I love you, sir." Mr. Burns: "Oh, hot dog. Thank you for making my last moments on earth socially awkward." Json.NET references a couple of assemblies that you wouldn’t expect for a JSON parser:

    • System.Data.Linq (LINQ to SQL)
    • System.Data.Entity (ADO.NET Entity Framework)

    Types from these assemblies are used to customize serialization behavior and make using Json.NET with them Just Work. While I always like things that Just Work, I’m not super happy about having dependencies on unrelated assemblies for small bits of functionality.

    My first thought is to ditch the assembly reference and create stand-in objects that internally use reflection to access the actual type. Instances of the original object would be replaced by the stand-in. Off the top of my head I think that would work but this seems like a problem that someone somewhere would have invested some time to fix properly.

    My question to you loyal reader is what is the best way to break .NET dependencies but keep the current level of functionality?

  • Efficient JSON with Json.NET – Reducing Serialized JSON Size

    Latest version of this guide: Reducing Serialized JSON Size

    ---

    One of the common problems encountered when serializing .NET objects to JSON is that the JSON ends up containing a lot of unwanted properties and values. This can be especially important when returning JSON to the client. More JSON means more bandwidth and a slower website.

    To solve the issue of unwanted JSON Json.NET has a range of built in options to fine tune what gets written from a serialized object.

    JsonIgnoreAttribute and DataMemberAttribute

    By default Json.NET will include all of a classes public properties and fields in the JSON it creates. Adding the JsonIgnoreAttribute to a property tells the serializer to always skip writing it to the JSON result.

    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; }
    }

    If a class has many properties and you only want to serialize a small subset of them then adding JsonIgnore to all the others will be tedious and error prone. The way to tackle this scenario is to add the DataContractAttribute to the class and DataMemberAttributes to the properties to serialize. This is opt-in serialization, only the properties you mark up with be serialized, compared to opt-out serialization using JsonIgnoreAttribute.

    [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 written by the serializer with an option of Formatting.Indented produces nicely formatted, easy to read JSON – great when you are developing. Formatting.None on the other hand keeps the JSON result small, skipping all unnecessary spaces and line breaks to produce the most compact and efficient JSON possible.

    NullValueHandling

    NullValueHandling is an option on the JsonSerializer and controls how the serializer handles properties with a null value. By setting a value of NullValueHandling.Ignore the JsonSerializer skips writing any properties that have a value of 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; }
    }
    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 { });
     
    // {
    //   "Name": "Bad Boys III",
    //   "Description": "It's no Bad Boys",
    //   "Classification": null,
    //   "Studio": null,
    //   "ReleaseDate": null,
    //   "ReleaseCountries": null
    // }
     
    string ignored = JsonConvert.SerializeObject(movie,
      Formatting.Indented,
      new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
     
    // {
    //   "Name": "Bad Boys III",
    //   "Description": "It's no Bad Boys"
    // }

    NullValueHandling can also be customized on individual properties using the a JsonPropertyAttribute. The JsonPropertyAttribute value of NullValueHandling will override the setting on the JsonSerializer for that property.

    DefaultValueHandling

    DefaultValueHandling is an option on the JsonSerializer and controls how the serializer handles properties with a default value. Setting a value of DefaultValueHandling.Ignore will make the JsonSerializer skip writing any properties that have a default value to the JSON result. For object references this will be null. For value types like int and DateTime the serializer will skip the default unitialized value for that value type.

    Json.NET also allows you to customize what the default value of an individual property is using the DefaultValueAttribute. For example if a string property called Department always returns an empty string in its default state and you didn't want that empty string in your JSON then placing the DefaultValueAttribute on Department with that value will mean Department is no longer written to JSON unless it has a value.

    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; }
    }
    Invoice invoice = new Invoice
    {
      Company = "Acme Ltd.",
      Amount = 50.0m,
      Paid = false,
      FollowUpDays = 30,
      FollowUpEmailAddress = string.Empty,
      PaidDate = null
    };
     
    string included = JsonConvert.SerializeObject(invoice,
      Formatting.Indented,
      new JsonSerializerSettings { });
     
    // {
    //   "Company": "Acme Ltd.",
    //   "Amount": 50.0,
    //   "Paid": false,
    //   "PaidDate": null,
    //   "FollowUpDays": 30,
    //   "FollowUpEmailAddress": ""
    // }
     
    string ignored = JsonConvert.SerializeObject(invoice,
      Formatting.Indented,
      new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.Ignore });
     
    // {
    //   "Company": "Acme Ltd.",
    //   "Amount": 50.0
    // }

    DefaultValueHandling can also be customized on individual properties using the a JsonPropertyAttribute. The JsonPropertyAttribute value of DefaultValueHandling will override the setting on the JsonSerializer for that property.

    IContractResolver

    For more flexibility the IContractResolver provides an interface to customize almost every aspect of how a .NET object gets serialized to JSON, including changing serialization behavior at runtime.

    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') });
     
    // {
    //   "AuthorName": "Brandon Sanderson",
    //   "AuthorAge": 34,
    //   "AuthorCountry": "United States of America"
    // }
     
    string startingWithB = JsonConvert.SerializeObject(book, Formatting.Indented,
      new JsonSerializerSettings { ContractResolver = new DynamicContractResolver('B') });
     
    // {
    //   "BookName": "The Gathering Storm",
    //   "BookPrice": 16.19
    // }

    kick it on DotNetKicks.com

  • Json.NET 3.5 Release 5 – .NET 2.0 Support, Error Handling & Databinding

    .NET 2.0 Support

    Json.NET now has .NET 2.0 support! The great thing about 2.0 support is Json.NET 1.3.1 can finally be retired. Going on 2 years old now, 1.3.1 is chock full of bugs that I have fastidiously ignored. Upgrade recommended!

    If you’re interested in the details I have previously blogged about adding .NET 2.0 support to Json.NET here.

    Error Handling

    Json.NET now has an Error event on the JsonSerializer and an OnErrorAttribute for handling serialization errors. When an error occurs you can access the exception, see details about the object and member the error occurred on and choose between setting the error as handled and letting it be thrown to your application.

    List<string> errors = new List<string>();
     
    List<DateTime> c = JsonConvert.DeserializeObject<List<DateTime>>(@"[
      ""2009-09-09T00:00:00Z"",
      ""I am not a date and will error!"",
      [
        1
      ],
      ""1977-02-20T00:00:00Z"",
      null,
      ""2000-12-01T00:00:00Z""
    ]",
      new JsonSerializerSettings
        {
          Error = delegate(object sender, ErrorEventArgs args)
            {
              errors.Add(args.ErrorContext.Error.Message);
              args.ErrorContext.Handled = true;
            },
          Converters = { new IsoDateTimeConverter() }
        });
     
    // 2009-09-09T00:00:00Z
    // 1977-02-20T00:00:00Z
    // 2000-12-01T00:00:00Z
     
    // The string was not recognized as a valid DateTime. There is a unknown word starting at index 0.
    // Unexpected token parsing date. Expected String, got StartArray.
    // Cannot convert null value to System.DateTime.

    In this example we are deserializing a JSON array to a collection of DateTimes. On the JsonSerializerSettings a handler has been assigned to the Error event which will log the error message and mark the error as handled.

    The result of deserializing the JSON is three successfully deserialized dates and three error messages: one for the badly formatted string, "I am not a date and will error!", one for the nested JSON array and one for the null value since the list doesn't allow nullable DateTimes. The event handler has logged these messages and Json.NET has continued on deserializing the JSON because the errors were marked as handled.

    Find more documentation about error handling here.

    DataBinding

    Lots of small additions have been made to LINQ to JSON to enable easy databinding.

    • Added type descriptor objects under the Newtonsoft.Json.Linq.ComponentModel namespace
    • Added ITypedList and IBindingList implementations to JContainer
    • Added INotifyPropertyChanging and INotifyPropertyChanged implementations to JObject

    As someone who is traditionally a web programmer it has been really interesting looking into the world of WPF databinding in more detail.

    Release vs Beta

    Finally one a minor detail the eagle eyed might have already noticed: from now on Json.NET updates are going to be called Releases rather than Betas.

    Changes

    Here is a complete list of what has changed since Json.NET 3.5 Beta 4.

    • New feature - Added .NET 2.0 support
    • New feature - Added serialization error handling via Error event on JsonSerializer and OnErrorAttribute
    • New feature - Added implicit conversions from primitive values to JValue
    • New feature - Added type descriptor objects to support LINQ to JSON databinding
    • New feature - Added ITypedList and IBindingList to JContainer
    • New feature - Added INotifyPropertyChanging and INotifyPropertyChanged to JObject
    • New feature - Added ConstructorHandling to allow object creation using non-public default constructors
    • New feature - Added roundtrip ADO.NET Entities serialization and deserialization
    • New feature - Added set indexer to JToken
    • Change - IsRequired now accepts null properties
    • Change - JsonSerializer now creates JObject/JArray when deserializing complex JSON to an object type
    • Change - Empty string to be deserialized as null for nullable types
    • Change - CloneNode on JToken renamed to CloneToken
    • Change - JProperty constructor that doesn't take a value made internal
    • Fix - Schema generation with negative enum values
    • Fix - Exception when loading JObject with multiple properties of the same name. Last property will be used
    • Fix - Exception when deserializing null value to List<Nullable<T>>
    • Fix - Generic type deserialization with type name tracking enabled

    Links

    Json.NET CodePlex Project

    Json.NET 3.5 Release 5 Download – Json.NET source code, documentation and binaries

  • Sunday Podcasts 3

    Homer, lighten up! You're making happy hour bitterly ironic.

    The Penny Arcade PodcastFor The Vin

    The authors of the comic website Penny Arcade record their thought process as they write a comic strip.

    In this episode they discuss their experiences of being molested at Disneyland by costumed characters, Swedes doing time in the big house for IP infringement, fantasy books and recruiting Vin Diesel into their DnD party.

    No TV, no beer make Homer something something.

    This American LifeThe Fix Is In

    Corporate crime is fascinating. Your average burglar isn’t the sharpest tool in the shed and neither is the crime he commits so it is interesting to see what happens when smart people decide that the law doesn’t apply to them. Examples: Enron scandal, Madoff’s $65 billion Ponzi scheme.

    The Fix Is In is a rerun show from 2000 about a global price fixing conspiracy and the executive, Mark Whitacre, who cooperated with the FBI in exposing it. Whitacre goes to amazing lengths to gather evidence and was described by the FBI as the most cooperative witness in their history. A film has even been made about his exploits: The Informant! – appropriately a comedy.

    Awesome.