Search code examples
c#json.net

How to change value of nested properties in a JObject?


I have a config.json that looks like this:

{
  "Field": {
    "FieldKey1": "FieldValue1",
    "FieldKey2": "FieldValue2"
  },
  "List": [
    "ListEntry1",
    "ListEntry2"
  ],
  "UnnestedKey": "UnnestedValue"
}

I can read access nested values the following way:

var x = await ConfigUtils.Get(configPath, "Field.FieldKey1");
Console.WriteLine(x.ToString());

with:

using Newtonsoft.Json;

public static async Task<JToken> Get(string filePath, string key)
{
    JObject jObject = await GetJObject(filePath);
    
    return jObject.SelectToken(key)
           ?? throw new KeyNotFoundException($"Key \"{key}\" doesn't exist in {filePath}.");
}
    
private static async Task<JObject> GetJObject(string filePath)
{
    string jsonString = await File.ReadAllTextAsync(filePath);
    
    JObject jObject = JObject.Parse(jsonString);
    
    return jObject;
}

which correctly prints "FieldValue1".

However, I can't figure out how to change a nested value in the config.json. If I try:

await ConfigUtils.UpdateValue(configPath, "Field.FieldKey1", "NewValue");

with:

using Newtonsoft.Json;

public static async Task UpdateValue(string filePath, string key, string value)
{
    JObject jObject = await GetJObject(filePath);

    jObject.AddOrReplace(key, value);

    await WriteJObject(jObject, filePath);
}

a new unnested key called Field.FieldKey1 ist added instead of changing the value of FieldKey1 inside Field.

How do I have to modify my UpdateValue method to work for nested values? I know I probably have to use jObject.SelectToken(key) like in my Get method, but I can't figure out how to go from there and am hopelessly confused regarding JToken, JProperty, JObject.


Solution

  • You can use Replace on the found token and JToken.FromObject to create a new value:

    var js = """
    {
      "Field": {
        "FieldKey1": "FieldValue1",
        "FieldKey2": "FieldValue2"
      },
      "List": [
        "ListEntry1",
        "ListEntry2"
      ],
      "UnnestedKey": "UnnestedValue"
    }
    """;
    
    var jObject = JObject.Parse(js);
    var selectToken = jObject.SelectToken("Field.FieldKey1");
    selectToken.Replace(JToken.FromObject("NewValue"));
    
    Console.WriteLine(JsonConvert.SerializeObject(jObject)); // {"Field":{"FieldKey1":"NewValue","FieldKey2":"FieldValue2"},"List":["ListEntry1","ListEntry2"],"UnnestedKey":"UnnestedValue"}