C# JSON

C# JSON tutorial shows how to work JSON data in C# using the classes of the standard library.

JSON

JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easily read and written by humans and parsed and generated by machines. The application/json is the official Internet media type for JSON. The JSON filename extension is .json.

In this article, we work with the C# standard library. There is also a popular third-party library called Json.NET.

System.Text.Json

The System.Text.Json namespace provides high-performance, low-allocating, and standards-compliant tools to work with JSON. The classes allow us to serialize objects into JSON text and deserialize JSON text to objects. The UTF-8 support is built-in.

C# JSON parse

The JsonDocument.Parse parses a stream as UTF-8-encoded data representing a single JSON value into a JsonDocument. The stream is read to completion.

Program.cs
using System.Text.Json;

string data = @" [ {""name"": ""John Doe"", ""occupation"": ""gardener""}, 
    {""name"": ""Peter Novak"", ""occupation"": ""driver""} ]";

using JsonDocument doc = JsonDocument.Parse(data);
JsonElement root = doc.RootElement;

Console.WriteLine(root);

var u1 = root[0];
var u2 = root[1];
Console.WriteLine(u1);
Console.WriteLine(u2);

Console.WriteLine(u1.GetProperty("name"));
Console.WriteLine(u1.GetProperty("occupation"));

Console.WriteLine(u2.GetProperty("name"));
Console.WriteLine(u2.GetProperty("occupation"));

In the example, we parse a simple JSON string.

using JsonDocument doc = JsonDocument.Parse(data);

We parse the JSON string into a JsonDocument.

JsonElement root = doc.RootElement;

We get the reference to the root element with the RootElement property.

var u1 = root[0];
var u2 = root[1];
Console.WriteLine(u1);
Console.WriteLine(u2);

With the [] operator, we get the first and the second subelements of the JSON document.

Console.WriteLine(u1.GetProperty("name"));
Console.WriteLine(u1.GetProperty("occupation"));

We get the properties of an element with GetProperty.

$ dotnet run
[ {"name": "John Doe", "occupation": "gardener"},
  {"name": "Peter Novak", "occupation": "driver"} ]
{"name": "John Doe", "occupation": "gardener"}
{"name": "Peter Novak", "occupation": "driver"}
John Doe
gardener
Peter Novak
driver

C# JSON enumerate

The JsonElement.EnumerateArray enumerates the values in the JSON array represented by a JsonElement.

Program.cs
using System.Text.Json;

string data = @" [ {""name"": ""John Doe"", ""occupation"": ""gardener""}, 
    {""name"": ""Peter Novak"", ""occupation"": ""driver""} ]";

using var doc = JsonDocument.Parse(data);
JsonElement root = doc.RootElement;

var users = root.EnumerateArray();

while (users.MoveNext())
{
    var user = users.Current;
    System.Console.WriteLine(user);

    var props = user.EnumerateObject();

    while (props.MoveNext())
    {
        var prop = props.Current;
        Console.WriteLine($"{prop.Name}: {prop.Value}");
    }
}

In the example, we enumerate the contents of the root element.

var users = root.EnumerateArray();

We get the array of subelements.

while (users.MoveNext())
{
    var user = users.Current;
    Console.WriteLine(user);
...

In a while loop, we go over the array of elements.

var props = user.EnumerateObject();

while (props.MoveNext())
{
    var prop = props.Current;
    Console.WriteLine($"{prop.Name}: {prop.Value}");
}

In the second while loop, we go over the properties of each element.

$ dotnet run
{"name": "John Doe", "occupation": "gardener"}
name: John Doe
occupation: gardener
{"name": "Peter Novak", "occupation": "driver"}
name: Peter Novak
occupation: driver

C# JSON serialize

The JsonSerializer.Serialize converts the value of a specified type into a JSON string.

Program.cs
using System.Text.Json;

var user = new User("John Doe", "gardener", new MyDate(1995, 11, 30));

var json = JsonSerializer.Serialize(user);
Console.WriteLine(json);

record MyDate(int year, int month, int day);
record User(string Name, string Occupation, MyDate DateOfBirth);

In the example, we convert a User object into a JSON string.

$ dotnet run
{"Name":"John Doe","Occupation":"gardener",
    "DateOfBirth":{"year":1995,"month":11,"day":30}}

C# JSON deserialize

The JsonSerializer.Deserialize parses the text representing a single JSON value into an instance of a specified type.

Program.cs
using System.Text.Json;

string json = @"{""Name"":""John Doe"", ""Occupation"":""gardener"",
    ""DateOfBirth"":{""year"":1995,""month"":11,""day"":30}}";

var user = JsonSerializer.Deserialize<User>(json);

Console.WriteLine(user);

Console.WriteLine(user?.Name);
Console.WriteLine(user?.Occupation);
Console.WriteLine(user?.DateOfBirth);

record MyDate(int year, int month, int day);
record User(string Name, string Occupation, MyDate DateOfBirth);

The example parses the JSON string into an instance of the User type.

C# JsonSerializerOptions

With JsonSerializerOptions, we can control the process of serialization with some options.

Program.cs
using System.Text.Json;

var words = new Dictionary<int, string>
{
    {1, "sky"},
    {2, "cup"},
    {3, "odd"},
    {4, "cloud"},
    {5, "forest"},
    {6, "warm"},
};

var r = JsonSerializer.Serialize(words, 
    new JsonSerializerOptions { WriteIndented = true });

Console.WriteLine(r);

Console.WriteLine("---------------------");

var d = JsonSerializer.Deserialize<Dictionary<int, string>>(r);

foreach (var (k, v) in d!)
{
    Console.WriteLine($"{k}: {v}");
}

With the WriteIndented option set, we enable indentation for pretty printing.

$ dotnet run
{
  "1": "sky",
  "2": "cup",
  "3": "odd",
  "4": "cloud",
  "5": "forest",
  "6": "warm"
}
---------------------
1: sky
2: cup
3: odd
4: cloud
5: forest
6: warm

C# Utf8JsonWriter

The Utf8JsonWriter provides a high-performance API for forward-only, non-cached writing of UTF-8 encoded JSON text.

Program.cs
using System.Text.Json;
using System.Text;

using var ms = new MemoryStream();
using var writer = new Utf8JsonWriter(ms);

writer.WriteStartObject();
writer.WriteString("name", "John Doe");
writer.WriteString("occupation", "gardener");
writer.WriteNumber("age", 34);
writer.WriteEndObject();
writer.Flush();

string json = Encoding.UTF8.GetString(ms.ToArray());

Console.WriteLine(json);

In the example, we create a new object and write it into a JSON string.

$ dotnet run
{"name":"John Doe","occupation":"gardener","age":34}

We can set the Indented option to true to beautify the JSON output.

Program.cs
using System.Text.Json;

string data = @" [ {""name"": ""John Doe"", ""occupation"": ""gardener""}, 
    {""name"": ""Peter Novak"", ""occupation"": ""driver""} ]";

JsonDocument jdoc = JsonDocument.Parse(data);

var fileName = @"data.json";
using FileStream fs = File.OpenWrite(fileName);

using var writer = new Utf8JsonWriter(fs, new JsonWriterOptions { Indented = true });
jdoc.WriteTo(writer);

In the example, we write a JSON string into a file. The data is prettyfied.

$ cat data.json 
[
    {
    "name": "John Doe",
    "occupation": "gardener"
    },
    {
    "name": "Peter Novak",
    "occupation": "driver"
    }
]

C# JSON Utf8JsonReader

The Utf8JsonReader orovides a high-performance API for forward-only, read-only access to UTF-8 encoded JSON text.

Program.cs
using System.Text.Json;

var fileName = @"/home/user7/data.json";
byte[] data = File.ReadAllBytes(fileName);
Utf8JsonReader reader = new Utf8JsonReader(data);

while (reader.Read())
{
    switch (reader.TokenType)
    {
        case JsonTokenType.StartObject:
            Console.WriteLine("-------------");
            break;
        case JsonTokenType.EndObject:
            break;
        case JsonTokenType.StartArray:
        case JsonTokenType.EndArray:
            break;
        case JsonTokenType.PropertyName:
            Console.Write($"{reader.GetString()}: ");
            break;
        case JsonTokenType.String:
            Console.WriteLine(reader.GetString());
            break;
        default:
            throw new ArgumentException();

    }
}

In the example, we read JSON data from a file with Utf8JsonReader. It provides a low-level API for reading JSON data. We read the data token by token.

$ dotnet run
-------------
name: John Doe
occupation: gardener
-------------
name: Peter Novak
occupation: driver

C# JSON parse async

In the following example, we read a stream asynchronously with JsonDocument.ParseAsync.

Program.cs
using System.Text.Json;

using var httpClient = new HttpClient();

var url = "https://raw.githubusercontent.com/dotnet/core/master/release-notes/releases-index.json";
var ts = await httpClient.GetStreamAsync(url);

using var resp = await JsonDocument.ParseAsync(ts);

var root = resp.RootElement.GetProperty("releases-index");

var elems = root.EnumerateArray();

while (elems.MoveNext())
{
    var node = elems.Current;
    Console.WriteLine(node);
}

The example reads all releases of the .NET Core framework, which are available as a JSON string on the project Github repository.

C# HttpClient GetFromJsonAsync

The GetFromJsonAsync method sends a GET request to the specified URL and returns the value that results from deserializing the response body as JSON in an asynchronous operation.

The method is an extension method from System.Net.Http.Json.

Program.cs
using System.Text.Json.Serialization;
using System.Net.Http.Json;

using var client = new HttpClient();

var url = "http://webcode.me/users.json";
var data = await client.GetFromJsonAsync<Users>(url);

if (data != null)
{
    foreach (var user in data.users)
    {
        Console.WriteLine(user);
    }
}

class Users
{
    public List<User> users { get; set; } = new();
}

class User
{
    [JsonPropertyName("id")]
    public int Id { get; set; }

    [JsonPropertyName("first_name")]
    public string FirstName { get; set; } = string.Empty;

    [JsonPropertyName("last_name")]
    public string LastName { get; set; } = string.Empty;

    [JsonPropertyName("email")]
    public string Email { get; set; } = string.Empty;

    public override string ToString()
    {
        return $"User {{ {Id}| {FirstName} {LastName}| {Email} }}";
    }
}

We create an asynchronous http request to a JSON resource. The JSON data is serialized into a list of User objects.

var data = await client.GetFromJsonAsync<Users>(url);

The GetFromJsonAsync is a convenience method which transforms JSON resource into C# collections.

class Users
{
    public List<User> users { get; set; } = new();
}

We need to create a specific class for the List collection.

class User
{
    [JsonPropertyName("id")]
    public int Id { get; set; }

    [JsonPropertyName("first_name")]
    public string FirstName { get; set; } = string.Empty;

    [JsonPropertyName("last_name")]
    public string LastName { get; set; } = string.Empty;

    [JsonPropertyName("email")]
    public string Email { get; set; } = string.Empty;

    public override string ToString()
    {
        return $"User {{ {Id}| {FirstName} {LastName}| {Email} }}";
    }
}

The JSON fields are mapped to class attributes.

$ dotnet run
User { 1| Robert Schwartz| rob23@gmail.com }
User { 2| Lucy Ballmer| lucyb56@gmail.com }
User { 3| Anna Smith| annasmith23@gmail.com }
User { 4| Robert Brown| bobbrown432@yahoo.com }
User { 5| Roger Bacon| rogerbacon12@yahoo.com }

In this article, we have worked with JSON data in C#.