Serializing and Deserializing JSON in C#

json serializer c#Serialization is a programming technique that converts an object in memory to a sequence of bytes. The serialized data is suitable for storage in files and databases, and can be sent to other computer systems across network protocols. In this short tutorial, you will see how to use features built-in to the .NET framework to serialize objects to JavaScript object notation (JSON). JSON stores objects and collections of objects in a human-readable, structured text format, and is commonly used in client/server architectures because of its high level of compatibility across a wide range of client programming languages.

To make full use of the information and examples presented here, you will need access to Microsoft Visual Studio and should have knowledge of the basics of programming in C#. You can find a useful tutorial for beginners, looking to learn the fundamentals of C#, at Udemy.com. Prior experience of working with JSON would also be an advantage. If you are encountering this for the first time, you should consider taking some JSON training to familiarize yourself with the core concepts and data types.

.NET Framework Classes

In version 3.5 (and in later versions) of the .NET framework, classes for serializing and deserializing to JSON are included in the framework. The main classes you will use are in System.Runtime.Serialization and System.Runtime.Serialization.Json.

The general process for serializing and deserializing JSON from C# is:

  1. Add a reference to the System.Runtime.Serialization library.
  2. Add using directives for System.Runtime.Serialization and System.Runtime.Serialization.Json.
  3. Define classes for the objects represented using DataContract and DataMember attributes.
  4. Create an instance of DataContractJsonSerializer.
  5. Use WriteObject() to serialize an object to a stream.
  6. Use ReadObject() to deserialize an object from a JSON stream.

Classes and Service Contracts

DataContracts are agreements between clients and servers that describe the information that is to be exchanged between them. Windows Communication Foundation (WCF) uses these extensively, however, you only need a small familiarity with them to use the DataContractJsonSerializer.

The DataContract attribute is used to mark a class as suitable for serialization/deserialization by the DataContractJsonSerializer. The example below defines a class with the minimum attributes needed to work with the serializer.

[DataContract]
class Spell
{
    [DataMember]
    public String cast;

    [DataMember]
    public String cooldown;

    [DataMember]
    public String cost;

    [DataMember]
    public String description;

    [DataMember]
    public String icon;

    [DataMember]
    public Int16 id;

    [DataMember]
    public String name;

    [DataMember]
    public String range;
}

When serialized, the resulting object notation looks like this:

{
    "cast":"Instance",
    "cooldown":"6 sec cooldown",
    "cost":"21% of base mana",
    "description":"Instantly shocks an enemy with frost...",
    "icon":"spell_frost_frostshock",
    "id":8056,
    "name":"Frost Shock",
    "range":"25 yd range"
}

The attribute DataMember can also be used to control certain elements in the serialization and deserialization process. It has five properties:

Property NameFunction
EmitDefaultValueSets whether or not to serialize the default values for the fields and properties being serialized.
IsRequiredWhether the member must be present in the JSON code when deserializing.
NameThe name of the member when serialized.
OrderThe order of the serialization or deserialization.
TypeIdWith derived classes, TypeId is a unique identifier for this attribute.

Attribute properties are included in the DataMember attribute by specifying the property name and value in parenthesis as shown in this modified version of the Spell class.

[DataContract]
class Spell
{
    [DataMember(Name="cast", IsRequired=true)]
    public String cast;

    [DataMember(Name = "cooldown", IsRequired = true)]
    public String cooldown;

    [DataMember(Name = "powerCost", IsRequired = true)]
    public String cost;

    [DataMember(Name = "description", IsRequired = true)]
    public String description;

    [DataMember(Name = "icon", IsRequired = false)]
    public String icon;

    [DataMember(Name = "id", IsRequired = true)]
    public Int16 id;

    [DataMember(Name = "name", IsRequired = true)]
    public String name;

    [DataMember(Name = "range", IsRequired = true)]
    public String range;
}

The example above uses the name property to change how the member cost appears in the serialized output. It also marks all members, apart from icon, as required.

Specifying the attribute properties can be useful when building a contract to an existing service that uses names that cannot be used in your class. When serialized, the code above produces the following JSON output:

{
    "cast":"Instance",
    "cooldown":"6 sec cooldown",
    "description":"Instantly shocks an enemy with frost...",
    "icon":"spell_frost_frostshock",
    "id":8056,
    "name":"Frost Shock",
    "powerCost":"21% of base mana",
    "range":"25 yd range"
}

Notice that the member cost is now named “powerCost” in the JSON code.

Serialization with the DataContractJsonSerializer

To serialize a .NET object to JSON, you must create an instance of DataContractJsonSerializer. The constructor for this class has one parameter: a reference to the type of .NET object that is to be serialized or deserialized.

Use the method WriteObject() to perform the serialization and send the output to the specified stream. It can work with most streams that are derived from System.IO.Stream – such as file streams, memory streams, and network streams.

Learn more about working with streams in C# at Udemy.com.

The example below assumes that the Spell class shown earlier is included in the namespace. It creates a new instance of Spell, and then serializes that object to JSON. The output is written to a System.IO.MemoryStream before being retrieved and sent to the console window.

/*
 * 
 * Udemy.com
 * Serializing and Deserializing JSON in C#
 * 
*/

using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;

namespace Serialization1
{
    class Program
    {
     static void Main(string[] args)
     {
      Spell frostShock = new Spell()
      {
       cast = "Instance",
       cooldown = "6 sec cooldown",
       description = "Instantly shocks an enemy with frost...",
       icon = "spell_frost_frostshock",
       id = 8056,
       name = "Frost Shock",
       cost = "21% of base mana",
       range = "25 yd range"
      };

      DataContractJsonSerializer js = new DataContractJsonSerializer(typeof(Spell));
     MemoryStream ms = new MemoryStream();
     js.WriteObject(ms, frostShock);

     Console.WriteLine("\r\nUdemy.com - Serializing and Deserializing JSON in C#\r\n");
     ms.Position = 0;
     StreamReader sr = new StreamReader(ms);
     Console.WriteLine(sr.ReadToEnd());
     sr.Close();
     ms.Close();
    }
 }
}

Arrays

When working with arrays of classes that have an established contract, the serialization will work with very few modifications to the code. You only need to change the type specified in the DataContractJsonSerializer‘s constructor. For example:

DataContractJsonSerializer js = new DataContractJsonSerializer(typeof(Spell[]));

Other .NET collections, such as generic lists, will also work but will often add in additional members used in their construction.

Deserialization with the DataContractJsonSerializer

Deserialization takes JSON-formatted data and converts it into a .NET object in memory. As with serialization, this relies on using an instance of DataContractJsonSerializer. Generally speaking, you will be loading JSON data from a stream (most likely a network stream from communicating with a web server), however, in this example the JSON is hardcoded into a string and then accessed through a MemoryStream.

To deserialize JSON from a stream, use the method ReadObject(). This returns an Object type that you can cast to the desired class.

class Program
{
    static void Main(string[] args)
    {
        String spellData = "{ \"id\": 133, \"name\": \"Fireball\", \"icon\": \"spell_fire_flamebolt\", \"description\": \"Hurls a fiery ball that causes 1,846 Fire damage.\", \"range\": \"40 yd range\", \"powerCost\": \"4% of base mana\", \"castTime\": \"2.25 sec cast\"}";

        DataContractJsonSerializer js = new DataContractJsonSerializer(typeof(Spell));
        MemoryStream ms = new MemoryStream(System.Text.ASCIIEncoding.ASCII.GetBytes(spellData));

        Spell fireBall = (Spell)js.ReadObject(ms);
        Console.WriteLine("\r\nUdemy.com - Serializing and Deserializing JSON in C#\r\n");
        Console.WriteLine("Spell: " + fireBall.name);
        Console.WriteLine("Description: " + fireBall.description);
        ms.Close();
    }
}

If you use this example with the version of Spell defined with the IsRequired properties, then the deserialization will fail. The JSON code does not include two of the fields. Change the IsRequired property to false (for both of those members) and the deserialization will succeed.

Other Types of Serialization in C#

JSON is not the only type of serialization that you can do using the .NET framework. You can also serialize objects to binary streams, XML, SOAP, and completely custom formats. These are advanced techniques and may require you to expand your knowledge of the language and the framework.

Take a comprehensive course in C#, from beginner to advanced, at Udemy.com.