Working with JSON in C#: Using System.Text.Json

Rupen Anjaria
5 min readJul 30, 2024

--

How to serialize and deserialization JSON in C# using the System.Text.Json namespace.

Note: You can try examples shown in this articles using your favorite online C# compiler like ShartLab.io.

What is JSON?

JSON stands for JavaScript Object Notation and it is primarily used to establish communication between two systems that may or may not be on the same platform. Earlier days were using XML, however, XML difficult to generate and parse and is less human friendly.

Compare to that JSON is easy to understand, write and light weight.

What is System.Text.JSON and why we need it in C# anyway?

System.Text.JSON is a namespace, which means it contains classes, helpers and extension methods to handle various operations related to JSON object. Below are the main reasons why we need it:

  1. Serialization/Deserialization: It refers to conversion of a C# object to JSON (Serialization) string or from JSON string to C# object (Deserialization).
  2. Custom Conversion: We can create a custom converter to handle very specific scenarios while while converting. It can include, ignoring certain properties, renaming certain properties etc.
  3. Partial JSON Reading: Let’s say we have a large and complex JSON object and we just need to parse some part of it. We can do this without converting entire JSON to C# object using methods available in the namespace.
  4. Stream Support: We can incrementally generate JSON object, just like streaming data on the fly. For example, we are reading a long list and would like to generate JSON based on certain conditions.
  5. Memory Efficient: It uses Span<T> and Memory<T> to efficiently use memory.

Let’s learn more about above offering by examples.

Serialization/Deserialization

Let’s see a very basic example of Serialization:

using System;
using System.Text.Json;

public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}

public class Program
{
public static void Main()
{
Person person = new() { Name = "John", Age = 30 };

// Serialize to JSON
string jsonString = JsonSerializer.Serialize(person);
Console.WriteLine(jsonString);

// Deserialize from JSON
Person deserializedPerson = JsonSerializer.Deserialize<Person>(jsonString);
Console.WriteLine($"Name: {deserializedPerson.Name}, Age: {deserializedPerson.Age}");
}
}
Output

{"Name":"John","Age":30}
Name: John, Age: 30

Here we have declared a C# class called Person. Later using JsonSerializer.Serialize method, which takes C# object as an argument and returns string, we converted our Person object to a JSON string {"Name":"John", "Age": 30}. Next, we used the same string to convert it back to C# object using JsonSerializer.Deserialize<Person>(jsonString).

Simple, right?

Custom Conversion

Let’s say we would like to ignore the Age property while Serializing. Here is how we can do it:

using System;
using System.Text.Json;
using System.Text.Json.Serialization;

public class Person
{
public string Name { get; set; }

[JsonIgnore]
public int Age { get; set; }
}

public class Program
{
public static void Main()
{
Person person = new() { Name = "John", Age = 30 };

// Serialize to JSON
string jsonString = JsonSerializer.Serialize(person);
Console.WriteLine(jsonString);

// Deserialize from JSON
Person deserializedPerson = JsonSerializer.Deserialize<Person>(jsonString);
Console.WriteLine($"Name: {deserializedPerson.Name}, Age: {deserializedPerson.Age}");
}
}
Output

{"Name":"John"}
Name: John, Age: 0

We added another namespace System.Text.Json.Serialization and just decorated the property we don’t want in serialization by attribute[JsonIgnore]. The output of JSON string will be without Age property. Note that deserialization indicated Age as 0, this is because of default value of int type.

This is particularly useful for properties that are sensitive, irrelevant for certain operations, or redundant in the JSON representation of the object.

Partial JSON Reading

Let’s say we received a string from an API response, the string represents very large and complex JSON object, however, we just need some part of it. Here is how we can achieve it:

using System;
using System.Text.Json;

public class Program
{
public static void Main()
{
string jsonString = @"{
""FirstName"": ""John"",
""LastName"": ""Doe"",
""Age"": 30,
""Email"": ""john.doe@example.com"",
""Address"": {
""Street"": ""123 Main St"",
""City"": ""Anytown"",
""ZipCode"": ""12345""
}
}";

// Parse the JSON string using JsonDocument
using (JsonDocument document = JsonDocument.Parse(jsonString))
{
// Access the root element
JsonElement root = document.RootElement;

// Read properties
string firstName = root.GetProperty("FirstName").GetString();
string lastName = root.GetProperty("LastName").GetString();
int age = root.GetProperty("Age").GetInt32();
string email = root.GetProperty("Email").GetString();

// Access nested object
JsonElement address = root.GetProperty("Address");
string street = address.GetProperty("Street").GetString();
string city = address.GetProperty("City").GetString();
string zipCode = address.GetProperty("ZipCode").GetString();

// Print out the values
Console.WriteLine("Person Details:");
Console.WriteLine($"FirstName: {firstName}");
Console.WriteLine($"LastName: {lastName}");
Console.WriteLine($"Age: {age}");
Console.WriteLine($"Email: {email}");
Console.WriteLine("Address:");
Console.WriteLine($"Street: {street}");
Console.WriteLine($"City: {city}");
Console.WriteLine($"ZipCode: {zipCode}");
}
}
}
Output

Person Details:
FirstName: John
LastName: Doe
Age: 30
Email: john.doe@example.com
Address:
Street: 123 Main St
City: Anytown
ZipCode: 12345

In above example, we are receiving user details including his address. If we have to convert it to real C# object, the we have to define C# class and use deserialization, however, if the purpose is to just get some part without needing to create C# class then we can do it by using JsonDocument.Parse method. It accepts JSON string and returns JsonDocument object. Using JsonDocument we can further get its inner properties.

Streaming Support

The Utf8JsonWriterclass in System.Text.Json allows you to write JSON data in a streaming manner, which can be useful for generating large JSON documents or for scenarios where you need incremental JSON writing.

Here, we’ll create a simple example where we have a list of objects representing people, and we use Utf8JsonWriter to generate a JSON output.

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.Json;

public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public string Email { get; set; }
}

public class Program
{
public static void Main()
{
var people = new List<Person>
{
new Person { FirstName = "John", LastName = "Doe", Age = 30, Email = "john.doe@example.com" },
new Person { FirstName = "Jane", LastName = "Smith", Age = 25, Email = "jane.smith@example.com" },
new Person { FirstName = "Michael", LastName = "Johnson", Age = 45, Email = "michael.johnson@example.com" },
};

using (var stream = new MemoryStream())
using (var writer = new Utf8JsonWriter(stream, new JsonWriterOptions { Indented = true }))
{
writer.WriteStartArray();

foreach (var person in people)
{
writer.WriteStartObject();
writer.WriteString("FirstName", person.FirstName);
writer.WriteString("LastName", person.LastName);
writer.WriteNumber("Age", person.Age);
writer.WriteString("Email", person.Email);
writer.WriteEndObject();
}

writer.WriteEndArray();
writer.Flush();

string jsonString = Encoding.UTF8.GetString(stream.ToArray());
Console.WriteLine("Generated JSON:");
Console.WriteLine(jsonString);
}
}
}
Output

Generated JSON:
[
{
"FirstName": "John",
"LastName": "Doe",
"Age": 30,
"Email": "john.doe@example.com"
},
{
"FirstName": "Jane",
"LastName": "Smith",
"Age": 25,
"Email": "jane.smith@example.com"
},
{
"FirstName": "Michael",
"LastName": "Johnson",
"Age": 45,
"Email": "michael.johnson@example.com"
}
]

Using Utf8JsonWriter allows you to generate JSON data efficiently and incrementally. Above example shows how to write a list of objects to a JSON array, ensuring that each object’s properties are serialized in a streaming manner. This approach can be particularly useful for large datasets or for applications that require high performance and low memory overhead.

Conclusion

JSON is a global standard for data exchange and there would be plenty of scenarios where dealing between JSON and C# will be necessary. This article have barely scratch the surface of functionalities offered bySystem.Text.JSON. There are plenty other functionalities worth checking out. If your program is dealing with extensive JSON and C# objects then it’s advised to spend some time in learning about capabilities offered by this namespace classes.

--

--

No responses yet