Working with JSON

Learn how to use the System.Text.Json namespace to serialize C# objects into JSON format, deserialize JSON back into objects, and seamlessly read and write JSON files asynchronously.

JSON (JavaScript Object Notation) is the industry standard format for data exchange, configuration files, and web APIs. It is a lightweight, text-based format that is easy for humans to read and write, and easy for machines to parse and generate.

Modern .NET provides the System.Text.Json namespace. This built-in library delivers high-performance JSON manipulation without relying on third-party packages. The two primary operations we perform with JSON are serialization and deserialization.

Serialization (C# object to JSON)

Serialization is the process of converting a .NET object (like a class or struct) into a JSON string. We use the JsonSerializer.Serialize method to convert a C# object into a JSON string.

C# 14.0
using System.Text.Json;
var course = new Course { Title = ".NET Fundamentals", Author = "John Doe", DurationInHours = 5 };
string jsonString = JsonSerializer.Serialize(course);
Console.WriteLine(jsonString);
public class Course
{
public string Title { get; set; } = string.Empty;
public string Author { get; set; } = string.Empty;
public int DurationInHours { get; set; }
}
  • Line 1: We import the System.Text.Json namespace to access the serialization engine.

  • Line 3: We instantiate and populate our C# object.

  • Line 5: We pass the object into JsonSerializer.Serialize, which returns a compact JSON-formatted string.

  • Lines 8–13: We define the data model at the bottom of the file to comply with top-level statement rules.

If we run this code, the output is a single, minified line of text:

{"Title":".NET Fundamentals","Author":"John Doe","DurationInHours":5}

Formatting options

By default, the serializer produces a minified string to save space. While this is efficient for network transfers, it is difficult for developers to read. We can customize the output using the JsonSerializerOptions class.

C# 14.0
using System.Text.Json;
var course = new Course { Title = ".NET Fundamentals", Author = "John Doe", DurationInHours = 5 };
var options = new JsonSerializerOptions
{
WriteIndented = true
};
string formattedJson = JsonSerializer.Serialize(course, options);
Console.WriteLine(formattedJson);
public class Course
{
public string Title { get; set; } = string.Empty;
public string Author { get; set; } = string.Empty;
public int DurationInHours { get; set; }
}
  • Lines 5–8: We configure a new options object and set WriteIndented to true.

  • Line 10: We pass the options object as an additional parameter to the Serialize method.

The output is now formatted with line breaks and indentation, making it human-readable:

{
"Title": ".NET Fundamentals",
"Author": "John Doe",
"DurationInHours": 5
}

Deserialization (JSON to C# object)

Deserialization is the exact opposite of serialization. It takes a JSON string and maps its keys and values back into strongly typed C# properties. We use the JsonSerializer.Deserialize<T> method for this process, where <T> represents the target C# type.

C# 14.0
using System.Text.Json;
string jsonInput = @"{ ""Title"": ""Advanced C#"", ""Author"": ""Jane Doe"", ""DurationInHours"": 8 }";
Course? deserializedCourse = JsonSerializer.Deserialize<Course>(jsonInput);
Console.WriteLine($"Course: {deserializedCourse?.Title}, Duration: {deserializedCourse?.DurationInHours}h");
public class Course
{
public string Title { get; set; } = string.Empty;
public string Author { get; set; } = string.Empty;
public int DurationInHours { get; set; }
}
  • Line 3: We define a raw JSON string using the @ symbol to allow escaped quotes ("").

  • Line 5: We call Deserialize<Course>, instructing the compiler to read the JSON and construct a new Course object.

  • Line 7: We access the properties of the newly created C# object using the null-conditional operator (?.).

Reading an existing JSON file

In many real-world scenarios, we read pre-existing JSON files manually added to our project. The following example demonstrates how to read an existing JSON file and deserialize it into a C# object. First, we create a file named course.json in our project directory.

// File: course.json
{
"Title": "Mastering Entity Framework",
"Author": "Alice Smith",
"DurationInHours": 12
}
A standard JSON file representing a course

Next, we write the C# logic to locate this file, read its contents asynchronously, and map those contents to our strongly typed model.

C# 14.0
{
"Title": "Mastering Entity Framework",
"Author": "Alice Smith",
"DurationInHours": 12
}
  • Line 5: We use Path.Combine to securely create a cross-platform file path pointing to our course.json file.

  • Line 8: We use await File.ReadAllTextAsync to read the entire file into a string without blocking the thread. The unmanaged file handle is automatically opened and safely disposed.

  • Line 11: We pass the text into JsonSerializer.Deserialize<Course>, which maps the JSON properties to our C# class properties.

  • Line 13: We output the dynamically loaded data to the console.

Writing JSON to a file

Once we have our serialized JSON string, we often need to save it to disk. We can combine System.Text.Json with the asynchronous file operations we learned previously.

C# 14.0
using System.IO;
using System.Text.Json;
var course = new Course { Title = "Advanced C#", Author = "Jane Doe", DurationInHours = 8 };
var options = new JsonSerializerOptions { WriteIndented = true };
// Serialize the object into a JSON string
string jsonString = JsonSerializer.Serialize(course, options);
// Safely construct the file path
string filePath = Path.Combine(Directory.GetCurrentDirectory(), "exported_course.json");
// Write the JSON string to a file asynchronously
await File.WriteAllTextAsync(filePath, jsonString);
Console.WriteLine($"Successfully wrote JSON to {filePath}");
// Read the same file back asynchronously
string readBackJson = await File.ReadAllTextAsync(filePath);
Course? verifiedCourse = JsonSerializer.Deserialize<Course>(readBackJson);
Console.WriteLine($"Verified Course Data:");
Console.WriteLine($"Title: {verifiedCourse?.Title}");
Console.WriteLine($"Author: {verifiedCourse?.Author}");
Console.WriteLine($"Duration: {verifiedCourse?.DurationInHours}h");
public class Course
{
public string Title { get; set; } = string.Empty;
public string Author { get; set; } = string.Empty;
public int DurationInHours { get; set; }
}
  • Line 8: We serialize our object into a formatted JSON string.

  • Line 11: We construct the cross-platform file path, targeting a new file named exported_course.json.

  • Line 14: We use await File.WriteAllTextAsync to safely write the string to the disk without blocking the thread. The unmanaged file handle is automatically managed and disposed of.

  • Lines 19–25: We read the exact same file back from the disk, deserialize it, and print the restored object’s properties to verify the full write-read cycle succeeded.