How to use JsonNode in C#
By FoxLearn 3/6/2025 7:48:13 AM 14
It allows you to work with JSON as a mutable DOM comprised of JsonNode objects (JsonObject
, JsonArray
, JsonValue
), enabling you to read, write, and modify JSON efficiently.
Consider the following JSON that represents a book:
{ "Title": "The Great Gatsby", "Authors": ["F. Scott Fitzgerald"], "PublishedYear": 1925 }
Modifying JSON with JsonNode
To modify this JSON string using JsonNode
, follow these steps:
using System.Text.Json; using System.Text.Json.Nodes; // Load the JSON as a DOM var bookJson = "{\"Title\":\"The Great Gatsby\",\"Authors\":[\"F. Scott Fitzgerald\"],\"PublishedYear\":1925}"; var jsonNode = JsonNode.Parse(bookJson); // Modify the 'PublishedYear' jsonNode["PublishedYear"] = 2023; // Convert back to a JSON string var jsonOptions = new JsonSerializerOptions() { WriteIndented = true }; var updatedJson = jsonNode.ToJsonString(jsonOptions); Console.WriteLine(updatedJson);
Output:
The output will reflect the updated value of the PublishedYear
property:
{ "Title": "The Great Gatsby", "Authors": [ "F. Scott Fitzgerald" ], "PublishedYear": 2023 }
If you're looking for alternatives to JsonNode
when avoiding class-based (de)serialization:
- For writing JSON, consider using an anonymous type or serializing a dictionary.
- For reading JSON, you could use
JsonDocument
for fast, read-only access or deserialize into a dynamic object.
Using JsonNode
, you can create JSON without raw strings:
var book = new JsonObject() { ["Title"] = "The Great Gatsby", ["Authors"] = new JsonArray("F. Scott Fitzgerald"), ["Details"] = new JsonObject() { ["Genre"] = "Novel", ["Pages"] = 180 } }; // Convert to JSON string var jsonOptions = new JsonSerializerOptions() { WriteIndented = true }; var bookJsonString = book.ToJsonString(jsonOptions); System.IO.File.WriteAllText(@"C:\temp\book.json", bookJsonString);
This generates and writes the following content to the file:
{ "Title": "The Great Gatsby", "Authors": [ "F. Scott Fitzgerald" ], "Details": { "Genre": "Novel", "Pages": 180 } }
Modifying Existing JSON
You can also modify existing JSON:
var book = JsonNode.Parse(bookJson); // Add a new property book["Rating"] = 5; // Modify the title book["Title"] = "The Great Gatsby (Revised Edition)"; var jsonOptions = new JsonSerializerOptions() { WriteIndented = true }; Console.WriteLine(book.ToJsonString(jsonOptions));
Output:
The updated JSON will look like this:
{ "Title": "The Great Gatsby (Revised Edition)", "Authors": [ "F. Scott Fitzgerald" ], "PublishedYear": 1925, "Rating": 5 }
Removing a Property
To remove a property:
book.AsObject().Remove("Rating");
Adding to an Array
To add a new author to the Authors
array:
book["Authors"].AsArray().Add("Another Author"); Console.WriteLine(book.ToJsonString(jsonOptions));
Output:
{ "Title": "The Great Gatsby (Revised Edition)", "Authors": [ "F. Scott Fitzgerald", "Another Author" ], "PublishedYear": 1925 }
Adding a Property Without Overwriting an Existing One
You can use the null-coalescing assignment operator (??=) to add a property only if it doesn’t already exist. This is helpful when you want to ensure existing properties remain unchanged.
Consider the following JSON representing a book:
{ "Title": "The Great Gatsby" }
Adding a Property
Suppose you want to add a property called Rating
with a default value of 5, but you don’t want to overwrite it if it already exists. Here’s how to do that with the ??= operator:
var bookJson = "{\"Title\":\"The Great Gatsby\"}"; var book = JsonNode.Parse(bookJson); // Add the 'Rating' property if it doesn't already exist book["Rating"] ??= 5; var currentRating = (int)book["Rating"]; Console.WriteLine($"Book has a rating of {currentRating}");
Output:
Book has a rating of 5
Now, if the JSON string already has the property defined as "Rating": 8
, running the same code would not overwrite the property:
var bookJsonWithRating = "{\"Title\":\"The Great Gatsby\", \"Rating\":8}"; var bookWithRating = JsonNode.Parse(bookJsonWithRating); // Attempt to add the 'Rating' property bookWithRating["Rating"] ??= 5; var currentRatingWithExisting = (int)bookWithRating["Rating"]; Console.WriteLine($"Book has a rating of {currentRatingWithExisting}");
Output:
Book has a rating of 8
Reading JSON
While the primary purpose of JsonNode is to modify JSON, you may also need to read values.
For instance, consider the following JSON:
{ "Title": "The Great Gatsby", "Authors": ["F. Scott Fitzgerald"], "PublishedYear": 1925, "Started": "2022-01-01T00:00:00" }
Here’s how you can read the Started
property and get its value safely:
var bookWithStarted = JsonNode.Parse(bookJsonWithRating); var started = (DateTime?)bookWithStarted["Started"]; if (started.HasValue) { Console.WriteLine($"Book started being written in year {started.Value.Year}"); } else { Console.WriteLine("Start date is not available."); }
If the Started
property exists, the output will be:
Book started being written in year 2022
If the property doesn’t exist, it will display:
Start date is not available.
Handling Errors
When attempting to read a property, you may encounter casting issues. For instance, if the JSON is malformed like this:
{ "Title": "The Great Gatsby", "Started": 1 }
Reading Started
as a DateTime
would throw an exception:
var bookWithInvalidStarted = JsonNode.Parse(bookJsonWithRating); var startedInvalid = (DateTime?)bookWithInvalidStarted["Started"]; // This will throw an exception
Safely Attempting to Read
To avoid such exceptions, you can use TryGetValue()
to safely retrieve the underlying value:
DateTime? startedSafe = null; bookWithInvalidStarted["Started"]?.AsValue().TryGetValue(out startedSafe); if (startedSafe.HasValue) { // Use the value } else { Console.WriteLine("Property is missing or isn't a DateTime"); }
This outputs a generic error message:
Property is missing or isn't a DateTime
Case Sensitivity
By default, JsonNode is case-sensitive. To handle properties in a case-insensitive manner, you can configure it as follows:
var jsonNodeOptions = new JsonNodeOptions() { PropertyNameCaseInsensitive = true }; var bookCaseInsensitive = JsonNode.Parse(bookJsonWithRating, jsonNodeOptions); Console.WriteLine((int?)bookCaseInsensitive["rating"]); // This will work even if the case doesn't match
This will output the value regardless of case:
8
You can add properties conditionally, read values while modifying, and handle case sensitivity as described above. This makes JsonNode a versatile choice for working with JSON in C#.
- How to Get Status Codes with HttpClient in C#
- How to use TimeZoneInfo in C#
- How to Get key with the max value in a dictionary in C#
- How to Get and send JSON with HttpClient in C#
- How to Deserialize JSON as a stream in C#
- TimeZoneInfo with current UTC offset in C#
- How to Parser a CSV file in C#
- How to read configuration from appsettings.json in C#