LightSpeed 3 Released

No children have ever meddled with the Republican Party and lived to tell about it.

The guys at Mindscape have just released the third version of LightSpeed.

For anyone that doesn’t know LightSpeed is an ORM for .NET and is far and away my favourite. Over the last couple of years it has been exciting to see the progress LightSpeed has made as a product and it has matured to the point where I can’t of any additional features I could want from it.

LINQ Support++

The two big additions in LightSpeed 3.0 for me are full LINQ support and database migrations. I’m a bit of a fiend when it comes to writing complex SQL so it is great that LightSpeed now has the LINQ support to keep up with the crazy queries I throw at it.

Homer's Brain: "Don't you get it? You've got to use reverse psychology." Homer: "That sounds too complicated." Homer's Brain: "OK, don't use reverse psychology." Homer: "All right, I will!"

(note: a boring sample query from the Mindscape blog post... I write LINQ that is illegal in some countries...)

Database Migrations

I haven’t had the chance to check out LightSpeed 3.0’s database migration features yet but I know pain of putting together SQL change scripts. I’m looking forward to using it.

But, Aquaman, you cannot marry a woman without gills. You’re from two different worlds... Oh, I’ve wasted my life.

And More

The change log for LS3 is impressively large, I’ve barely scratched the surface. Congrats to the Mindscape guys for making the best .NET ORM even better.

Check LightSpeed 3.0 out here.

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