Serializing and deserializing JSON objects are an important part of all software engineer routines. In this article, we will learn different techniques about how to deserialize a complex JSON object in C# and check, with a performance benchmark, which is the fastest technique.

To download the source code for this article, you can visit our GitHub repository.

That said, let’s start.

Preparing Environment

Let’s take a look at a complex JSON object that we are going to use in this article:

Support Code Maze on Patreon to get rid of ads and get the best discounts on our products!
Become a patron at Patreon!
{
    "id": "854e469f-76ec-4036-b10e-2305d5063cc4",
    "name": "Microsoft",
    "cofounders": [{
        "id": "0d61b68c-f05e-4e6c-822d-6769578f241c",
        "name": "Bill Gates"
    }, 
    {
        "id": "3ef95ce8-7302-470c-afc2-f59d2a3cb2df",
        "name": "Paul Allen"
    }],
    "employees": [{
        "id": "6416b2c8-9f8f-4a8e-9f74-ce919ee08a2f",
        "fullName": "Jane Doe",
        "anualSalary": 150000,
        "position": {
            "id": "b57fe795-0fbf-4da8-bab8-c6a2ba4e709d",
            "description": "Engineer Manager"
        },
        "benefits": [{
            "id": "e3257cb7-0984-42c1-b432-d640dfb0a029",
            "additional": 3000,
            "description": "Additional Bonus"
        }, {
            "id": "7cda860a-695b-4aac-956a-fb7245c75ef3",
            "additional": 2500,
            "description": "Paid Vacation"
        }]
    }
    ...
    ]
}

You can check the full JSON object at this link.

Now, let’s define the POCO (Plain Old CLR Object) classes we are going to use to deserialize this JSON complex object.

Company:

public class Company
{
    public string? Id { get; set; }
    public string? Name { get; set; }
    public List<Cofounder>? Cofounders { get; set; }
    public List<Employee>? Employees { get; set; }
}

Cofounder:

public class Cofounder
{
    public string? Id { get; set; }
    public string? Name { get; set; }
}

Employee:

public class Employee
{
    public string? Id { get; set; }
    public string? FullName { get; set; }
    public int AnualSalary { get; set; }
    public Position? Position { get; set; }
    public List<Benefit>? Benefits { get; set; }
}

Position:

public class Position
{
    public string? Id { get; set; }
    public string? Description { get; set; }
}

Benefit:

public class Benefit
{
    public string? Id { get; set; }
    public int Additional { get; set; }
    public string? Description { get; set; }
}

Now that we have our environment ready, let’s begin deserializing JSON.

Using System.Text.Json To Deserialize a Complex JSON

Our project is using .NET 6.0. That said, we don’t need to install any package to use the System.Text.Json library. However, it is good to mention that, if we are using any framework earlier than .NET Core 3.0, it is necessary to install this library using the Install-Package System.Text.Json command in the package manager console.

There’s no secret to deserialize a JSON object. The System.Text.Json library provides us with a static class JsonSerializer to help us with this task. 

Let’s create a new method to see how we can deserialize a JSON:

private Company? DeserializeUsingGenericSystemTextJson(string json)
{
    var company = JsonSerializer.Deserialize<Company>(json, new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });

    return company;
}

As an input parameter, our method receives a JSON string. After the deserialization, it returns a nullable Company with all the data. 

Inside this method, we create a company variable that is going to receive our deserialized object. Then we call the Deserialize method from the JsonSerializer static class and voilà. We have our variable ready to return.

The Deserialize method receives two parameters, the first represents the JSON object we want to deserialize. The second parameter is optional but recommended. It represents the settings we want to use to deserialize the JSON:

new JsonSerializerOptions() { PropertyNameCaseInsensitive = true }

With the (PropertyNameCaseInsensitive) property, we inform the deserializer class not to distinguish lower- and uppercase, otherwise, it will assign null to the mismatch properties.

If we don’t want to use the generic deserialize, the JsonSerializer class provides us with the same method with another parameter:

var company = (Company?)JsonSerializer.Deserialize(json, typeof(Company), new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });

Note that we add a new parameter after the JSON. It represents the type we want to deserialize. Besides that, it is necessary to cast the result to the type we want. Without the cast, we are going to have a nullable object instead of the POCO class we defined earlier.

Using Newtonsoft.Json to Deserialize a Complex Json

When we are using a framework version earlier than .NET 3.0, it is recommended to use Newtonsoft.Json to serialize and deserialize objects.

To use this library, we have to run the Install-Package Newtonsoft.Json command in the package manager console.

Once the installation is complete, let’s add the Newtonsoft.Json namespace:

using Newtonsoft.Json;

Then, let’s create the method to deserialize the JSON using this library:

private Company? DeserializeUsingNewtonSoftJson(string json)
{
    var company = JsonConvert.DeserializeObject<Company>(json);

    return company;
}

Different from the System.Text.Json library, this time we are going to use a static class JsonConvert and the DeserializeObject generic method. Also, we don’t need to use the second parameter, becauseNewtonsoft.Json is case insensitive by default.

Anyway, this method gives us another overload. It allows us to pass, as the second parameter, a JsonSerializerSettings instance.

With JsonSerializerSettings we can set the culture we want to use when deserializing the JSON object. We can set the DateTime format and many other settings. 

We can check the full list at the Json.net documentation.

Benchmark Comparison

To define which is the fastest way to deserialize a complex JSON object, we are going to run a benchmark comparing the three ways we described in this article.

Let’s create a method to read a very big JSON file we have generated:

private string ReadJsonFile()
{
    using StreamReader reader = new(@$"{AppContext.BaseDirectory}\JsonFiles\VeryBigJson.json");
    return reader.ReadToEnd();
}

This JSON object contains a single company with one hundred cofounders and, fifty thousand employees. For each employee, we have ten benefits. The total file size is 35.2 MB. Since it is too big, you would have to download it from GitHub if you want to inspect it.

After running the benchmark we can inspect the result:

|                                Method |     Mean |    Error |   StdDev |
|-------------------------------------- |---------:|---------:|---------:|
| DeserializeUsingGenericSystemTextJson | 453.5 ms | 14.43 ms | 40.69 ms |
|        DeserializeUsingSystemTextJson | 400.9 ms |  7.99 ms | 22.00 ms |
| DeserializeUsingGenericNewtonsoftJson | 733.8 ms | 14.37 ms | 25.54 ms |

Analyzing these benchmark results, note that, we have a minimum difference of 53ms between the methods that are using System.Text.Json library. It implies that the generic approach is a tiny slower than when we are not using generic.

On the other hand, when we look at the third method, which uses the NewtonsoftJson library, the difference is around 330 ms slower than the fastest approach.

Taking into account that we are using a very big JSON with a 35MB file size, this difference is not too relevant when we are deserializing a small JSON. Nevertheless, a good practice would be using System.Text.Json whenever it is possible, once Microsoft is constantly improving this library. 

Using Json2Csharp Tip

To make it easier to define the POCO classes in C#, based on a JSON complex object, we can use the Json2Csharp website. There, we can use the JSON to C# converter option and check the Use Pascal Case checkbox to convert our JSON object.

Difference Between Simple and Complex Json Objects

There is no big difference between simple and complex JSON objects. It means that a complex JSON object has, in its composition, nested objects and collections. That said, the deserialization instructions are the same, however, our POCO classes are much simpler when we are using a simple JSON Object:

{
    "Title": "How to Copy Array Elements to New Array in C#",
    "LastUpdate": "2022-01-31T00:00:00.000",
    "Link": "https://code-maze.com/csharp-populate-array-same-value/"
}

And let’s see the representative POCO class:

public class Article
{
    public string? Title { get; set; }
    public DateTime LastUpdate { get; set; }
    public string? Link { get; set; }
}

Conclusion

In this article, we have seen different ways to deserialize a complex JSON object using C#.

We have learned an easy way to define POCO classes using the Json2Csharp website, the main difference between a simple and complex JSON object, some deserialization options, classes, and methods.

After a benchmark comparison, we have seen which library is recommended for each scenario and even if we choose the slower technique, the difference would not be too expressive, taking into account that both libraries are very efficient.

Liked it? Take a second to support Code Maze on Patreon and get the ad free reading experience!
Become a patron at Patreon!