Search code examples
c#jsonjson.net

Cannot add new elements to Json Array


I have a configuration Json file that contains a List of dictionaries.

{
  "Hardware": [
    {
      "Name": "name1",
      "Model": "model1"
    },
    {
      "Name": "name2",
      "Model": "model2"
    }
  ]
}

I am importing this Json into a variable using Newtonsoft.

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.IO;
using System.Windows.Forms;

namespace WindowsFormsApp2
{
    public partial class Form1 : Form
    {
        public JObject Parameters;

        public Form1()
        {
            InitializeComponent();
            using (StreamReader file = File.OpenText("../../configuration.json"))
            using (JsonTextReader reader = new JsonTextReader(file))
            {
                Parameters = (JObject)JToken.ReadFrom(reader);
            }
        }
    }
}

This seem to work well and I can do things like:

`Parameters["Hardware"][0]["Name"].ToString()`   -> returns "name1"

Now, I have two string variables with a new name and a new model (this variables come from a loop that iterates over a DataGridView, but that's not relevant to the question)

string Name = "name3";
string Model = "model3";

Following this question Creating JSON on the fly with JObject I have created a JToken containing this two variables, but I'm not sure how can I add them to Parameters["Hardware"]

I create a new JObject containing this name and model:

dynamic Aux = new JObject();
Aux.Name = "name3";
Aux.Model = "model3";

But if I try to do:

Parameters["Hardware"].Add(Aux);

It complains that JToken does not contain a definition for Add I'm not sure why Parameters["Hardware"] is a JToken and not a JArray.

I tried doing something Hacky like:

Parameters["Hardware"] = (JArray)Parameters["Hardware"];
Parameters["Hardware"].Add(Aux);

But the compiler still complains about Parameters["Hardware"] being a JToken and won;t let me compile.

This is quite a basic thing, so I'm sure I might be doing something wrong and an easy solution exists, I just cannot figure it out.

At the end I want to have Parameters["Hardware"] like

{
  "Hardware": [
    {
      "Name": "name1",
      "Model": "model1"
    },
    {
      "Name": "name2",
      "Model": "model2"
    },
    {
      "Name": "name3",
      "Model": "model3"
    }
  ]
}

So I can export it back to a Json file.

So far I only needed to read the data from the Json or modify it, which works well, but now that I have to add elements is where I'm facing some trouble.

I am happy to change the way I read the file, maybe storing it as a JObject is not the best. So any suggestion on how to end up with a list of dictionaries with added elements is welcome.


Solution

  • You are getting that error because the JObject indexer Parameters["Hardware"] is declared to return an object of type JToken:

    public JToken this[
      string propertyName
    ] { get; set; }
    

    And JToken, which is the abstract base class for JArray, JObject, JValue and so on, has no Add() method. You need to downcast to JArray, which does have an Add() method, like so

    ((JArray)Parameters["Hardware"]).Add(Aux); 
    

    Since c# is (mostly) statically typed and the indexer is declared to return JToken you can only use the methods of the abstract base class JToken. You must downcast to JArray to use JArray methods.

    For a discussion of the LINQ to JSON type hierarchy see JContainer, JObject, JToken and Linq confusion.