JSON.NET Array conversion - c#

I am trying to convert a JSON array to a C# dictionary.
My Box class has "id" and "color" properties.
{
"boxes" [
{"id":0, "color":"red"},
{"id":1, "color":"green"},
{"id":2, "color":"blue"}
]
}
I've tried a few things, but haven't had any luck getting this to work yet.
List<Box> jsonResponse = JsonConvert.DeserializeObject<List<Box>>(File.ReadAllText(filePath));

Well the thing is that your Dictionary is in nested property.
And even more - it's not really a dictionary. It is an array of objects where each object consists of two fields - id and color (whereas in dictionary we have key-value pairs).
You could deserialize your json into anonymous object with correct structure and then get the array of boxes out of it and convert it to dictionary:
var box = new { id = 0, name = "" };
var jsonObj = new { boxes = new[] { box } };
var dict = JsonConvert.DeserializeAnonymousType(myJson, jsonObj).boxes
.ToDictionary(b => b.id, b => b.name);

JSON doesn't need {} at the top level - so you can just have your list of items in {}'s surrounded by [].
[
{"id":0, "color":"red"},
{"id":1, "color":"green"},
{"id":2, "color":"blue"}
]

Related

C# Unable to modify Json with Newtonsoft

I have a string type variable named final and it contains the following Json:
{
"Game": {
"Player_Decks": {
"1": {
"Card_List": "2_Yellow,1_Blue,Reverse_Green,5_Yellow,5_Red,7_Red,2_Blue",
"Card_Count": 7
},
"2": {
"Card_List": "5_Blue,9_Green,4_Yellow,6_Green,0_Red,2_Green,6_Yellow",
"Card_Count": 7
}
},
"Deck_NoCards": {}
}
}
My code looks like this: (taken from here: https://www.newtonsoft.com/json/help/html/ModifyJson.htm)
JObject rss = JObject.Parse(final);
JObject channel = (JObject)rss["Game.Player_Decks.1"];
channel.Property("Card_Count").AddAfterSelf(new JProperty("new", "New value"));
I want to add another value after Card_Count, but I have a feeling that my string isn't "compatible" or something. What can be done here to fix my problem?
Reposting comment as answer here:
You cannot access the nested object using a dotted path "Game.Player_Decks.1". Instead you need to individually address each property within each object.
JObjects are effectively an array of named properties, JObject implements IDictionary<string, JToken?> so as long as each child element is also a JObject then you can use the string index to reference the element in the next level.
JObject game = (JObject)rss["Game"];
JObject decks = (JObject)game["Player_Decks"];
JObject channel = (JObject)decks["1"];
channel.Property("Card_Count").AddAfterSelf(new JProperty("new", "New value"));
The following syntax should also work:
JObject channel = rss["Game"]["Player_Decks"]["1"] as JObject;
Also, have you considered using a Json Array instead of properties named 1, 2, etc. like so:
{
"Game": {
"Player_Decks": [
{
"Card_List": "2_Yellow,1_Blue,Reverse_Green,5_Yellow,5_Red,7_Red,2_Blue",
"Card_Count": 7
},
{
"Card_List": "5_Blue,9_Green,4_Yellow,6_Green,0_Red,2_Green,6_Yellow",
"Card_Count": 7
}
],
"Deck_NoCards": {}
}
}
and accessed as:
JObject rss = JObject.Parse(final);
JObject game = (JObject)rss["Game"];
JArray decks = (JArray)game["Player_Decks"];
JObject deck1 = (JObject)decks[0];

How get List of JSON Objects from within a JSON object (non-array) (NOT Deserializing)

I'm using C# with Json.NET NuGet.
I have JSON that looks like this:
{
"pre" : "",
"options": {
"0001" : {
"id" : "0001",
"desc" : "first"
},
"0002" : {
"id" : "0002",
"desc" : "second"
},
"0003" : {
"id" : "0003",
"desc" : "third"
}
},
"post" : ""
}
How can I query the above Json to get a List<JObject> with the 3 option items in it?
Or/Also How can I get just the second item where item 2 should be:
{
"id" : "0002",
"desc" : "second"
}
I've tried stuff like
var items = json.SelectTokens("options[*]").ToList();
and
var item = json.SelectTokens("options[1]");
but those clearly don't work.
EDIT:
In case I wasn't clear I DO NOT want to deserialize. I want a List<JObject>.
Your json is valid but your thinking of this json is not quite accurate.
You are thinking that options have a list of objects that you want to iterate over, but, thats not the case. options is not a list but an object that has more objects within it.. Not an array.
You can access each of the element within the JObject by first looking up its properties. Properties are 0001, 0002 etc. Once you have those, you can iterate over the properties of options and get the values you need.
JObject options = (JObject)JObject.Parse(json)["options"];
// Get a list of all tokens within this object.
List<JObject> allObjects = new List<JObject>();
foreach (var node in options.Properties())
allObjects.Add((JObject)options[node.Name]);
// Access the IDs
allObjects.ForEach(x => Console.WriteLine(x["id"].ToString()));
// Access the 2nd ID only
Console.WriteLine(); // Just to space it out.
Console.WriteLine(allObjects[1]["id"].ToString());
Output
0001
0002
0003
0002
You could create the required List using Linq. For example,
var list = ((JObject)JObject.Parse(str)["options"])
.Properties()
.Select(x=>x.Value)
.Cast<JObject>()
.ToList();
For accessing the second element, you could use
var secondId = (string)list[1]["id"];
var secondDesc = (string)list[1]["desc"];
I was actually close but trying too hard:
var items = json.SelectToken("options").ToList();
I was unable to figure out how to get a single option from a query but since I got the whole list I did it like this:
var item = json.SelectToken("options").ToList()[1];

JSON array to C# Dictionary

How do I convert a JSON array like this
[{"myKey":"myValue"},
{"anotherKey":"anotherValue"}]
to a C# Dictionary with json.net or system classes.
json.net can serialize directly to a dictionary, but only if you feed it an object, not an array.
Maybe converting to array of KeyValuePairs will help
using System.Linq;
var list = JsonConvert.DeserializeObject<IEnumerable<KeyValuePair<string, string>>>(jsonContent);
var dictionary = list.ToDictionary(x => x.Key, x => x.Value);
For anyone interested - this works, too:
Example JSON:
[{"device_id":"VC2","command":6,"command_args":"test args10"},
{"device_id":"VC2","command":3,"command_args":"test args9"}]
C#:
JsonConvert.DeserializeObject<List<JObject>>(json)
.Select(x => x?.ToObject<Dictionary<string, string>>())
.ToList()
Its quite simple actually :
lets say you get your json in a string like :
string jsonString = #"[{"myKey":"myValue"},
{"anotherKey":"anotherValue"}]";
then you can deserialize it using JSON.NET as follows:
JArray a = JArray.Parse(jsonString);
// dictionary hold the key-value pairs now
Dictionary<string, string> dict = new Dictionary<string, string>();
foreach (JObject o in a.Children<JObject>())
{
foreach (JProperty p in o.Properties())
{
string name = p.Name;
string value = (string)p.Value;
dict.Add(name,value);
}
}
I found that using a list of KeyValuePairs didn't work. I got the right number of elements but they had null Keys and Values.
In the end the only solution that worked for me was deserialising to a list of dictionaries (which each had a single kvp element).
The data must to be sent as follows (format):
"Values": [
{"Key" : "abc" , "Value": 23.14},
{"Key" : "abc1" , "Value": 23.11},
{"Key" : "abc2" , "Value": 23.17},
{"Key" : "abc3" , "Value": 23.19}
]
thereby, the converting process will work. It worked fine to me in my attempt to convert from JSON to dictionary<string,decimal>
Since you can only deserialize from an object, do just that by manipulating the JSON string a little first. Wrap it in an object:
json = String.Format("{{\"result\":{0}}}", json);

ASP.NET getting indexed values when deserializing JSON into a dynamic object

So I have a JSON string that I am passing from an AJAX call to my controller. I have a list of indexed values that I am passing into a dynamic object.
I deserialize the JSON with
JsonConvert.DeserializeObject<dynamic>(s)
This is the output from that dynamic object:
"RolePermissions[0].RolePermissionId": "269",
"RolePermissions[0].HasAccess": "false",
"RolePermissions[1].RolePermissionId": "270",
"RolePermissions[1].HasAccess": "false",
"RolePermissions[2].RolePermissionId": "271",
"RolePermissions[2].HasAccess": "true",
"RolePermissions[3].RolePermissionId": "272",
"RolePermissions[3].HasAccess": "false"
When I try to access the a property of the object with
ssObj.RolePermissions[0].RolePermissionId
I get a RuntimeBinderException. I have tried to use JObject.Parse, which works great, but for some reason, the values in the array become out of order.
Any help would be greatly appreciated. Thanks!
When you try to do RolePermissions[0].RolePermissionId you are trying to access a nested collection containing an object with a property RolePermissionId at index 0. But your JSON doesn't represent a hierarchy of objects, it represents a single flat object with key/value pairs whose keys contain periods and brackets. Since c# identifiers don't allow such characters so you have no way to access such property values using dynamic directly.
Instead, your options include:
Take advantage of the fact that JsonConvert.DeserializeObject<dynamic>(s) actually returns a JObject and use its dictionary indexer:
var ssObj = JsonConvert.DeserializeObject<dynamic>(s);
var rolePermissionId = (string)ssObj["RolePermissions[0].RolePermissionId"];
If you prefer a slightly more typed solution, you could deserialize to a Dictionary<string, dynamic>:
var ssDict = JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(s);
var rolePermissionId = (string)ssDict["RolePermissions[0].RolePermissionId"];
Or for a much more statically typed solution, parse explicitly to a JObject and use LINQ to JSON:
var jObj = JObject.Parse(s);
var rolePermissionId = (string)jObj["RolePermissions[0].RolePermissionId"];
Sample fiddle showing the various options.
If you are in control of the data being sent via AJAX then make sure the data sent is properly formatted.
In order to be able to deserialize variable s like:
var ssObj = JsonConvert.DeserializeObject<dynamic>(s);
and access the resulting object in this manner:
ssObj.RolePermissions[0].RolePermissionId
then the JSON value in s, based on your sample and desired behavior, would have to look like this:
{
"RolePermissions": [
{
"RolePermissionId": "269",
"HasAccess": "false"
},
{
"RolePermissionId": "270",
"HasAccess": "false"
},
{
"RolePermissionId": "271",
"HasAccess": "true"
},
{
"RolePermissionId": "272",
"HasAccess": "false"
}
]
}
This quick unit test showed that it is possible to get indexed values when deserializing JSON into a dynamic object
[TestClass]
public class UnitTest1 {
[TestMethod]
public void GetIndexedValuesWhenDeserializingJSONIntoDynamicObject() {
var s = #"
{
'RolePermissions': [
{
'RolePermissionId': '269',
'HasAccess': 'false'
},
{
'RolePermissionId': '270',
'HasAccess': 'false'
},
{
'RolePermissionId': '271',
'HasAccess': 'true'
},
{
'RolePermissionId': '272',
'HasAccess': 'false'
}
]
}
";
var ssObj = JsonConvert.DeserializeObject<dynamic>(s);
var result = ssObj.RolePermissions[0].RolePermissionId;
Assert.AreEqual("269", (string)result);
}
}
So you need to make sure you are sending well formatted JSON to your controller to achieve desired behavior.

How do I get the value in a generic Dictionary?

I have a json string like this:
{
"ipaddress": "xxx",
"hostname": "comcast.xxx",
"popup": {
"position": "1256",
"pagename": "home"
}
}
In my Windows Form code I've been using JavaScriptSerializer for phare those line to dictionary.
var obj = new JavaScriptSerializer().Deserialize<Dictionary<string, object>>(json);
It is working fine at the moment, but I don't know how to get value inside popup? Because it's another dictionary.
[7] = {[popup, System.Collections.Generic.Dictionary`2[System.String,System.Object]]}
The fastest (yet unsafe) way of doing it is like this is via the indexer:
First extract the first dictionary and cast, since the first dictionary will yield an object of type object:
var popup = (Dictionary<string, object>)obj["popup"];
Then, you extract the values based on keys:
var position = popup["position"];
var pagename = popup["pagename"];
If you're not sure both keys will exist in the result, you can use Dictionary.TryGetValue if they exist:
obj position;
if (!popup.TryGetValue("position", out position))
{
// Key isn't in the dictionary.
}
Use JSON .Net, then simply:
JObject dynJson = JObject.Parse(jsonString);
followed by:
string data = dynJson["popup"]["position"];
JObject.Parse

Categories