Serialisation – JSON in C#, using Json.NET
Last week we compared a number of different data-interchange formats and I explained why my current favourite is JSON.
JSON’s syntax is very simple. So easy in fact, that it can be expressed on a single page.
This makes it easy to remember and write. Further, it makes writing a JSON parser very easy as well.
However, there already are many solutions for all major, and many smaller languages and environments.
So instead of reinventing the wheel, today I would like to give an introduction to Json.NET, the library I have been using to read and write JSON for about two years now.
I will take a very practical approach, giving an overview over the basic features. Further, I will highlight some of the additional features of the library that I have found useful in the past, and we will extend the library to allow for parsing of custom non-trivial types.
Json.NET basics
The basic usage of Json.Net is very simple.
The static class JsonConvert
has a number of methods to serialise to and deserialise from JSON.
It does so by using reflection to do all the heavy lifting for us, and no additional code on our side is needed.
The library is very flexible however, and most of its behaviour can be extended or overridden as needed.
We will use the following class from last week (albeit slightly simplified) to show basic serialisation and deserialisation.
class UnitTemplate
{
public string Name { get; set; }
public float Speed { get; set; }
public float Health { get; set; }
public List<string> Weapons { get; set; }
}
Serialisation
To serialise an object using Json.NET, we can simply pass it to JsonConvert.SerialiseObject()
Doing so with the object created as follows:
var template = new UnitTemplate
{
Name = "Tank",
Speed = 0.5f,
Health = 100,
Weapons = new List<string>
{ "big cannon", "small turret" }
};
yields this result:
{"Name":"Tank","Speed":0.5,"Health":100.0,"Weapons":["big cannon","small turret"]}
By default Json.NET will use no white space to improve the size of the output. However, by passing Formatting.Indented
to the above method’s formatting parameter, we can easily get the following output.
{
"Name": "Tank",
"Speed": 0.5,
"Health": 100.0,
"Weapons": [
"big cannon",
"small turret"
]
}
This is much more readable, and I would prefer this in almost all cases unless the size is a definite problem.
Note that this method works great for pretty much any type, including dictionaries and other collections. It also works great with anonymous types, allowing easy dumping of arbitrary data to a file in a structured way without having to create container types that are not used for anything else.
Apart from its additional parameters, we can also modify this method’s behaviour in a number of different ways. One of them is by using attributes, to control how our data is serialised.
They can be found in the official documentation, but there is one I have found particularly useful:
JsonIgnoreAttribute
This attribute is an easy way to prevent Json.NET from serialising properties that do not have to be. This is particularly useful if a type contains a property which does not have any backing data on its own, but infers its value from other properties.
Imagine for example a rectangle type with properties Width
, Height
and Area
. The area would neither have to be stored in memory, nor in JSON, but could always be calculated on the fly when needed.
By simply placing [JsonIgnore]
in front of our Area
property, Json.NET will ignore it when serialising.
Deserialisation
Deserialisation with Json.NET is almost equally simple to serialisation.
We can simply use the generic method JsonConvert.DeserializeObject<T>()
.
There also is a non-generic overload, but if we know the type of data we are expecting – which should be the case most of the time – using the generic version will give us type-safety and relieves us from having to do additional parsing.
Without giving an example, it suffices to say that parsing either of the JSON from above results in a new object identical to the one we had before.
Serialiser settings and converters
Json.Net’s static serialisation and deserialisation method’s also take additional parameters.
One of them is the JsonSerializerSettings
, which can be used to control the process in a variety of ways.
If you are looking into using Json.NET for more than minor things, I encourage you to take a look at the type’s documentation`.
Alternatively, the static methods take a list of JsonConverters
.
These converters are in essence the meat of the Json.NET library, determining how different values and types are written and read.
The library comes with several implementations that can be quite useful. My personal favourite is StringEnumConverter
, which reads and writes enum values as their string names, instead of as numbers, greatly improving readability.
Custom converters – extending Json.NET
In additional to the provided converters, we can also write our own by extending JsonConverter
.
Take for example the following converter, which serialises System.Color
into a hexadecimal string, and back.
class ColorConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var c = (Color)value;
var rgbInt = c.A << 24 | c.R << 16 | c.G << 8 | c.B;
var hexString = string.Format("#{0:X8}", rgbInt);
writer.WriteValue(hexString);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var hexString = (string)reader.Value;
var rgbInt = int.Parse(hexString.Substring(1), NumberStyles.HexNumber);
return Color.FromArgb(rgbInt);
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(Color);
}
}
Note that Json.NET already serialises Color
without any problems. The example merely serves to show how easy it is to create custom converters.
- For more advanced examples, I invite you to take a look at the serialisation namespace in my C# graphics library.
JsonSerializer
One last useful feature of Json.NET I will mention here is the JsonSerializer
class.
This class can be used to keep both the state from JsonSerializerSettings
as well as a list of converters. As a result, one only has to configure it once and can then use it as many times as needed.
Conclusion
In this post, I gave a short introduction into the basics of serialising and deserialising JSON in C#, using Json.NET. I hope this has been useful, and please let me know if you have any questions. Also make sure to leave a comment if you would like me to go further into this or any other topic.
Enjoy the pixels!
Reference: | Serialisation – JSON in C#, using Json.NET from our NCG partner Paul Scharf at the GameDev<T> blog. |