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.
Line 1: We import the
System.Text.Jsonnamespace 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.
Lines 5–8: We configure a new options object and set
WriteIndentedtotrue.Line 10: We pass the options object as an additional parameter to the
Serializemethod.
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.
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 newCourseobject.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}
Next, we write the C# logic to locate this file, read its contents asynchronously, and map those contents to our strongly typed model.
Line 5: We use
Path.Combineto securely create a cross-platform file path pointing to ourcourse.jsonfile.Line 8: We use
await File.ReadAllTextAsyncto 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.
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.WriteAllTextAsyncto 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.