C# – Examples of using JsonDocument to read JSON

You can use the JsonDocument class when you want to read and process JSON without having to deserialize the whole thing to an object.

For example, let’s say you have the following JSON object representing wind variables:

{
  "speed": 4,
  "deg": 95,
  "gust": 3.27
}
Code language: JSON / JSON with Comments (json)

Now let’s say you’re only interested in the wind speed. Instead of having to deserialize this into a Wind object, you can use JsonDocument to read the JSON string and get the speed value:

using System.Text.Json;

using (var jsonDoc = JsonDocument.Parse(json))
{
	JsonElement speed = jsonDoc.RootElement.GetProperty("speed");
	Console.WriteLine($"Wind speed = {speed.GetInt32()}");
}
Code language: C# (cs)

This outputs the following:

Wind speed = 4Code language: plaintext (plaintext)

In this article, I’ll show examples of using JsonDocument in various scenarios.

Note: For brevity, I’ll exclude “using System.Text.Json;” from the remaining code examples. Assume it’s needed.

Check if a property exists

When you use JsonElement.GetProperty(), it’ll throw a KeyNotFoundException if the the property doesn’t exist. If you want to check if a property exists without throwing an exception, use TryGetProperty().

Here’s an example of using TryGetProperty():

using (var jsonDoc = JsonDocument.Parse(json))
{
	if (jsonDoc.RootElement.TryGetProperty("speed", out JsonElement speed))
	{
		Console.WriteLine($"Speed property exists and has int value = {speed.GetInt32()}");
	}
}
Code language: C# (cs)

This outputs the following:

Speed property exists and has int value = 4Code language: plaintext (plaintext)

Loop through a JSON object’s properties

To loop through a JSON object’s properties, use EnumerateObject().

For example, let’s say you want to loop through the following coder JSON object:

{
   "Name": "Bob",
   "Language": "C#",
   "YearsExperience": 15
}
Code language: JSON / JSON with Comments (json)

Use EnumerateObject() to get the properties. This gives you a JsonElement for each property. You can loop through them and look at the property names, types*, and values.

using (var jsonDoc = JsonDocument.Parse(json))
{
	foreach (var property in jsonDoc.RootElement.EnumerateObject())
	{
		Console.WriteLine($"{property.Name} ValueKind={property.Value.ValueKind} Value={property.Value}");
	}
}
Code language: C# (cs)

*Note: ValueKind is the property type.

This outputs the following:

Name ValueKind=String Value=Bob
Language ValueKind=String Value=C#
YearsExperience ValueKind=Number Value=15Code language: plaintext (plaintext)

This is useful in many scenarios, such as manually mapping or when you need to examine which properties were included.

Loop through a JSON array

Use EnumerateArray() to be able to loop through the values in a JSON array.

For example, let’s say you want to loop through and sum the integers in this JSON array:

[1, 2, 3, 4, 5]Code language: JSON / JSON with Comments (json)

Use EnumerateArray() to get a JsonElement for every object in the JSON array. You can loop through it like any other collection (or use a Linq method, like the following):

using System.Linq;

using (var jsonDoc = JsonDocument.Parse(json))
{
	int sum = jsonDoc.RootElement.EnumerateArray().Sum(n => n.GetInt32());
	Console.WriteLine($"Sum of numbers in array = {sum}");
}
Code language: C# (cs)

This outputs the following:

Sum of numbers in array = 15Code language: plaintext (plaintext)

This is useful for things like aggregating values or when you need to search the array for a specific value / object.

Deserialize a nested object

You can use GetProperty() to get a specific nested object as a JsonElement, and then call Deserialize<T>() to deserialize it into a target type. This is useful for when you’re only interested in a small part of a JSON string.

I’ll show an example of this by getting a JSON response from an API (from openweatherapi.org), and deserializing just one of the nested objects (highlighted below):

{
    "coord": {
        "lon": -87.629,
        "lat": 41.8803
    },
    "weather": [
        {
            "id": 804,
            "main": "Clouds",
            "description": "overcast clouds",
            "icon": "04d"
        }
    ],
    "base": "stations",
    "main": {
        "temp": 270.65,
        "feels_like": 266.52,
        "temp_min": 268.47,
        "temp_max": 272.31,
        "pressure": 1026,
        "humidity": 56
    },
    "visibility": 10000,
    "wind": {
        "speed": 3.13,
        "deg": 80,
        "gust": 4.47
    },
    "clouds": {
        "all": 100
    },
    "dt": 1646932263,
    "sys": {
        "type": 2,
        "id": 2005153,
        "country": "US",
        "sunrise": 1646914253,
        "sunset": 1646956253
    },
    "timezone": -21600,
    "id": 4887398,
    "name": "Chicago",
    "cod": 200
}
Code language: JSON / JSON with Comments (json)

This example is using HttpClient to get JSON from the openweathermap API. Then it’s using JsonDocument to parse the HttpClient response stream. Finally, it’s deserializing the “wind” nested object by using GetProperty() + Deserialize<Wind>():

var response = await httpClient.GetAsync(OPENWEATHERMAP_URL);
response.EnsureSuccessStatusCode();
var stream = await response.Content.ReadAsStreamAsync();

using (var jsonDoc = await JsonDocument.ParseAsync(stream))
{
	var windElement = jsonDoc.RootElement.GetProperty("wind");
	return windElement.Deserialize<Wind>(jsonOptions);
}
Code language: C# (cs)

This returns the following Wind object (shown as JSON):

{
  "Speed": 3.13,
  "Deg": 80,
  "Gust": 4.47
}
Code language: JSON / JSON with Comments (json)

Leave a Comment