You cannot modify JsonElement
, it is completely immutable. Instead, you must deserialize it to some mutable type such as JsonNode
, modify the mutable type, then re-serialize back to JsonElement
. The following method does that:
public static class JsonExtensions
{
public static JsonNode TryAddPropertyToArrayElements<TProperty>(this JsonNode node, string name, TProperty value)
{
if (node is JsonArray array)
foreach (var obj in array.OfType<JsonObject>())
obj[name] = JsonSerializer.SerializeToNode(value);
return node;
}
public static JsonElement TryAddPropertyToArrayElements<TProperty>(this JsonElement element, string name, TProperty value) =>
element.ValueKind == JsonValueKind.Array
? JsonSerializer.SerializeToElement(JsonSerializer.Deserialize<JsonNode>(element)!.TryAddPropertyToArrayElements(name, value))
: element;
public static object? TryAddPropertyToArrayElements<TProperty>(this object? obj, string name, TProperty value) =>
obj switch
{
JsonElement e => e.TryAddPropertyToArrayElements(name, value),
JsonNode n => n.TryAddPropertyToArrayElements(name, value),
null => null, // JSON values that are null are deserialized to the c# null value, not some element or node of type null
_ => throw new ArgumentException("Unexpected type ${obj}"),
};
}
Then you would use it as follows:
metas["key-1"] = metas["key-1"]?
.TryAddPropertyToArrayElements("newproperty", "test value");
Demo fiddle #1 here.
Obviously all this serialization is somewhat inefficient. To avoid the extra serialization, assuming you generated your dictionary via deserialization, you could deserialize with JsonSerializerOptions.UnknownTypeHandling = JsonUnknownTypeHandling.JsonNode
. This setting forces types declared as object
to be deserialized to JsonNode
rather than JsonElement
:
var inputOptions = new JsonSerializerOptions
{
UnknownTypeHandling = JsonUnknownTypeHandling.JsonNode,
};
var metas = JsonSerializer.Deserialize<Dictionary<string, object?>>(json, inputOptions)!;
If you do you will be able to mutate its values directly using the method JsonExtensions.TryAddPropertyToArrayElements<TProperty>(this JsonNode node, string name, TProperty value)
included above.
Notes:
JsonNode
and JsonSerializer.SerializeToElement()
were introduced in .NET 6 so if you are using an earlier version you will need to use a different approach.
Demo fiddle #2 here.