
Creating and Modifying JSON Using JsonNode in .NET
Author - Abdul Rahman (Bhai)
JSON
5 Articles
Table of Contents
What we gonna do?
Need to build JSON on the fly, or modify an existing JSON response before sending it? JsonNode is your answer. Unlike JsonDocument, which is read-only, JsonNode creates a mutable DOM that you can change, extend, and manipulate. In this article, we'll show you how to dynamically work with JSON in .NET without being locked into immutable structures.
Why we gonna do?
JsonDocument is fast, but it's frozen—once parsed, you can't modify it. What if you need to add, remove, or update properties in a JSON object? Or build a complex JSON payload from scratch without defining a class? That's where JsonNode shines.
JsonNode lives in the System.Text.Json.Nodes namespace and provides a flexible, mutable API for constructing and manipulating JSON. You can parse existing JSON, modify it, and serialize it back. Or you can build JSON from the ground up using object initializers. It's slower than JsonDocument, but the tradeoff is mutability and ease of use .
Think of it like this: JsonDocument is a photo—you can look at it, but you can't edit it. JsonNode is a Photoshop layer—you can tweak, add, delete, and rearrange as needed.
How we gonna do?
Here's how to create, modify, and manipulate JSON using JsonNode in .NET:
Step 1: Understanding the JsonNode Family
The System.Text.Json.Nodes namespace provides four key classes:
- JsonNode: The base class representing any JSON value
- JsonObject: Represents a JSON object (key-value pairs)
- JsonArray: Represents a JSON array (ordered list of values)
- JsonValue: Represents a primitive JSON value (string, number, boolean, null)
You can access child elements by index or property name, get the parent or root, and perform conversions between types.
Step 2: Parsing Existing JSON
Start by parsing a JSON string using JsonNode.Parse(). Unlike
JsonDocument, you don't need a using statement—JsonNode doesn't implement IDisposable.
string jsonString = """
{
"city": "Chennai",
"temperature": 15,
"conditions": ["cloudy", "windy"]
}
""";
JsonNode weatherNode = JsonNode.Parse(jsonString);
// Output the JSON as a formatted string
var options = new JsonSerializerOptions { WriteIndented = true };
Console.WriteLine(weatherNode.ToJsonString(options));
Step 3: Accessing Properties
Access properties using indexer syntax. You can chain property access for nested objects.
// Get a property value
string city = weatherNode["city"].GetValue<string>();
Console.WriteLine($"City: {city}"); // Output: City: Chennai
int temp = weatherNode["temperature"].GetValue<int>();
Console.WriteLine($"Temperature: {temp}°C");
// Access array elements
JsonArray conditions = weatherNode["conditions"].AsArray();
string firstCondition = conditions[0].GetValue<string>();
Console.WriteLine($"First condition: {firstCondition}");
// Output: First condition: cloudy
Step 4: Modifying Existing JSON
Here's where JsonNode really shines. You can add, remove, and update properties dynamically.
// Remove a property
JsonObject weatherObj = weatherNode.AsObject();
weatherObj.Remove("conditions");
// Add a new property
weatherObj["humidity"] = 75;
weatherObj["forecast"] = "Rain expected";
// Modify an existing property
weatherObj["temperature"] = 18;
Console.WriteLine(weatherNode.ToJsonString(
new JsonSerializerOptions { WriteIndented = true }
));
/* Output:
{
"city": "Chennai",
"temperature": 18,
"humidity": 75,
"forecast": "Rain expected"
}
*/
Step 5: Building JSON from Scratch
You can create complex JSON structures using object initializers—no parsing required.
var apiResponse = new JsonObject
{
["status"] = "success",
["timestamp"] = DateTime.UtcNow.ToString("o"),
["data"] = new JsonObject
{
["userId"] = 12345,
["username"] = "abdul_dev",
["roles"] = new JsonArray { "admin", "developer", "user" }
},
["metadata"] = new JsonObject
{
["version"] = "2.0",
["server"] = "api-01"
}
};
Console.WriteLine(apiResponse.ToJsonString(
new JsonSerializerOptions { WriteIndented = true }
));
/* Output:
{
"status": "success",
"timestamp": "2025-11-02T10:30:00.0000000Z",
"data": {
"userId": 12345,
"username": "abdul_dev",
"roles": ["admin", "developer", "user"]
},
"metadata": {
"version": "2.0",
"server": "api-01"
}
}
*/
Step 6: Working with JsonObject and JsonArray
Cast to JsonObject or JsonArray to access type-specific methods.
// Count properties in a JsonObject
JsonObject dataObj = apiResponse["data"].AsObject();
int propertyCount = dataObj.Count;
Console.WriteLine($"Data object has {propertyCount} properties");
// Get all property names
var keys = dataObj.Select(kvp => kvp.Key);
Console.WriteLine($"Keys: {string.Join(", ", keys)}");
// Output: Keys: userId, username, roles
// Work with JsonArray
JsonArray rolesArray = dataObj["roles"].AsArray();
rolesArray.Add("moderator"); // Add a new role
rolesArray.RemoveAt(0); // Remove "admin"
Console.WriteLine($"Updated roles: {rolesArray.ToJsonString()}");
// Output: Updated roles: ["developer","user","moderator"]
Step 7: Merging and Combining JSON
You can merge multiple JSON objects by adding properties from one to another.
var additionalData = new JsonObject
{
["email"] = "abdul@example.com",
["verified"] = true
};
// Add properties from additionalData to the existing data object
foreach (var kvp in additionalData)
{
dataObj[kvp.Key] = kvp.Value?.DeepClone();
}
Console.WriteLine(apiResponse.ToJsonString(
new JsonSerializerOptions { WriteIndented = true }
));
// Now "data" includes email and verified properties
Step 8: Converting Between JsonNode and Objects
You can deserialize a JsonNode into a strongly-typed object when needed.
public class UserData
{
public int UserId { get; set; }
public string Username { get; set; }
public List<string> Roles { get; set; }
public string Email { get; set; }
public bool Verified { get; set; }
}
// Deserialize the "data" node into a UserData object
UserData user = dataObj.Deserialize<UserData>();
Console.WriteLine($"User: {user.Username}, ID: {user.UserId}");
Console.WriteLine($"Roles: {string.Join(", ", user.Roles)}");
Summary
JsonNode gives you the power to build and modify JSON dynamically in .NET. Whether you're constructing API responses on the fly, transforming incoming data, or working with JSON that doesn't fit a predefined schema, JsonNode provides a flexible, mutable API that makes these tasks simple. Use it when you need to change JSON, and reach for JsonDocument when you just need to read it fast.