JContainer, JObject, JToken and Linq confusion
You don't really need to worry about JContainer
in most cases. It is there to help organize and structure LINQ-to-JSON into well-factored code.
The JToken
hierarchy looks like this:
JToken - abstract base class JContainer - abstract base class of JTokens that can contain other JTokens JArray - represents a JSON array (contains an ordered list of JTokens) JObject - represents a JSON object (contains a collection of JProperties) JProperty - represents a JSON property (a name/JToken pair inside a JObject) JValue - represents a primitive JSON value (string, number, boolean, null)
So you see, a JObject
is a JContainer
, which is a JToken
.
Here's the basic rule of thumb:
- If you know you have an object (denoted by curly braces
{
and}
in JSON), useJObject
- If you know you have an array or list (denoted by square brackets
[
and]
), useJArray
- If you know you have a primitive value, use
JValue
- If you don't know what kind of token you have, or want to be able to handle any of the above in a general way, use
JToken
. You can then check itsType
property to determine what kind of token it is and cast it appropriately.
JContainer
is a base class for JSON elements that have child items. JObject
, JArray
, JProperty
and JConstructor
all inherit from it.
For example, the following code:
(JObject)JsonConvert.DeserializeObject("[1, 2, 3]")
Would throw an InvalidCastException
, but if you cast it to a JContainer
, it would be fine.
Regarding your original question, if you know you have a JSON object at the top level, you can just use:
var jsonWork = JObject.Parse(json);var jsonObject1 = jsonWork["Object1"];
Most examples have simple json and I've googled "C# Newtonsoft parse JSON" more than once.
Here's a bit of a json file I was just asked to parse for a csv. The company name value is nested within many arrays / objects so it is semi-complicated in that regard.
{ "page": { "page": 1, "pageSize": 250 }, "dataRows": [ { "columnValues": { "companyName": [ { "name": "My Awesome Company", } ] } } ]}
var jsonFilePath = @"C:\data.json"; var jsonStr = File.ReadAllText(jsonFilePath); // JObject implementation for getting dataRows JArray - in this case I find it simpler and more readable to use a dynamic cast (below) //JObject jsonObj = JsonConvert.DeserializeObject<JObject>(jsonStr); //var dataRows = (JArray)jsonObj["dataRows"]; var dataRows = ((dynamic)JsonConvert.DeserializeObject(jsonStr)).dataRows; var csvLines = new List<string>(); for (var i = 0; i < dataRows.Count; i++) { var name = dataRows[i]["columnValues"]["companyName"][0]["name"].ToString(); // dynamic casting implemntation to get name - in this case, using JObject indexing (above) seems easier //var name2 = ((dynamic)((dynamic)((dynamic)dataRows[i]).columnValues).companyName[0]).name.ToString(); csvLines.Add(name); } File.WriteAllLines($@"C:\data_{DateTime.Now.Ticks}.csv", csvLines);