Deserialize Nested JSON with C# Without Class Declaration - c#

I am trying to deserialize an object dynamically but unsure what the syntax is:
The JSON looks like this:
"Id": 2750,
"Rev": 1,
"Fields": {
"System.AreaPath": "test",
"System.TeamProject": "proj",
"System.IterationPath": "Ipath",
"System.WorkItemType": "type"
}
I know they can be accessed like this:
var resultString = response.Content.ReadAsStringAsync().Result;
var jsonObject = JObject.Parse(resultString);
string ID= jsonObject["id"].ToString();
But I am not sure how to get to the values nested in Fields directly.
I know I can iterate through jsonObject["Fields"] but I want to access them via something like jsonObject["Fields\\System.AreaPath"].ToString(); or whichever is the correct syntax, if it exists that is.

Related

LINQ-TO-JSON cannot get value in array

I am trying to get values with LINQ-TO-JSON in this JSON-TREE, So far it looks good until i've approached this categories element.
I want to get the value "Teknik" from this value and this is what i've tried to far without success.
Name = json["items"][i]["categories"].Children().Value<string>() ?? "Not assigned"
Name = json["items"][i]["categories"][0].Value<string>() ?? "Not assigned"
Name = json["items"][i]["categories"].First.Value<string>()
But none of these results works for me. Please help!
You didn't post the actual JSON string and the "tree" doesn't help. The JSON string in Querying JSON with LINQ could be represented with a similar tree, so I'll assume that's your source data:
string json = #"{
'channel': {
'title': 'James Newton-King',
'link': 'http://james.newtonking.com',
'description': 'James Newton-King\'s blog.',
'item': [
{
'title': 'Json.NET 1.3 + New license + Now on CodePlex',
'description': 'Annoucing the release of Json.NET 1.3, the MIT license and the source on CodePlex',
'link': 'http://james.newtonking.com/projects/json-net.aspx',
'categories': [
'Json.NET',
'CodePlex'
]
},
{
'title': 'LINQ to JSON beta',
'description': 'Annoucing LINQ to JSON',
'link': 'http://james.newtonking.com/projects/json-net.aspx',
'categories': [
'Json.NET',
'LINQ'
]
}
]
}
}";
JObject rss = JObject.Parse(json);
The example shows two ways to access values, through indexers or LINQ queries.
Using indexers, you'd only need [0] to access the first category of an item, eg:
rss["items"][i]["categories"][0];
That returns a JValue object as a JObject. You can cast it directly to string to get its value, eg:
(string)rss["items"][i]["categories"][0]
Or to a JValue, if you want to handle it as a JSON object and read the Value property, eg:
(rss["items"][i]["categories"][0] as JValue).Value;
A LINQ query wouldn't need indexers. If you wanted to retrieve the Category names you could write :
var query= from item in rss["channel"]["item"]
from category in item["categories"]
select new {Name=(string)category};
Or
var query = from category in rss["channel"]["item"].SelectMany(item=>item["categories"])
select new {Name=(string)category};
Or
var query = rss["channel"]["item"].SelectMany(item=>item["categories"])
.Select(category=>new {Name=(string)category});

How take this json path in newtonsoft.json C#

I have been building an application where JSON will be provided from a user API. It should read the data from the JSON using JSONPath and persist the selected portions. I am trying to do this using Json.Net (Newtonsoft). The following JSON is a sample:
{
// other properties here and different structure here
"Data": [
{
"Code": "625087",
"Name": "Customer Name",
"Email": "test#hfgidfgd.com"
},
{
"Code": "625087",
"Name": "Customer Name",
"Email": "test#hfgidfgd.com"
},
{
"Code": "625087",
"Name": "Customer Name",
"Email": "test#hfgidfgd.com"
}
],
// other properties here and different structure here
}
I would like to extract the array presented by the Data property content using JSONPath and convert it to List<Dictionary<string, object>> to manipulate in my application.
In tools like jsonpath.com the following JSONPath query works fine but with Newtonsoft it does not:
// get that json
string content = GetJson();
var jo = JObject.Parse(content);
var jsonPath = "$..Data.*";
var jsonPathResult = jo.SelectTokens(jsonPath, true /* to get error when it is not found */ );
Instead I got the exception:
Property '*' not valid on JArray.
If I do the JSONPath like this:
var jsonPath = "$..Data"; // same for just: "Data"
var jsonPathResult = jo.SelectTokens(jsonPath);
I have to loop on the result with two nested foreach, what I think it is not an elegant solution:
var result = new List<Dictionary<string, object>>();
foreach (var jsonResult in jsonPathResult)
{
foreach (var item in jsonResult)
{
var fields = JsonConvert.DeserializeObject<Dictionary<string, object>>(item.ToString());
// some adjusts on the fields dictionary will be applied here...
result.Add(fields);
}
}
Is there any way to get the result to take a single loop the only the content of Data property?
As shown in JSONPath - XPath for JSON, the syntax for an array element wildcard is [*]. Thus your code should look like:
var jsonPath = "$..Data[*]";
var result = jo.SelectTokens(jsonPath, true /* to get error when it is not found */ )
.Select(o => o.ToObject<Dictionary<string, object>>())
.ToList();
Here I am using JToken.ToObject<T>() to deserialize each array element directly to a Dictionary<string, object>> without re-serializing to a string.
Sample working .Net fiddle.

Read Dynamic Json

I have a requirement to read the json in which keys are vary and store into dictionary in C#.net. I am using Newtonsoft json. I am deserializing like below.
var inputData = JsonConvert.DeserializeObject<dynamic>(myObj)
If the keys are fixed I can do like below.
var val = inputData.Account;
But here keys are dynamic. Below is my json data.
{
"data": {
"Account": "150.80",
"Name": "XYZ",
"Description": "Some Value"
}
}
Here name value pairs may change. i.e., It may have like below also.
{
"data": {
"Cost": "154.80",
"Type": "S1234",
"Period": "Some Value"
}
}
How to access dynamic keys and store into a dictionary.
EDIT: This answer was for the previous posted question, not the newly revised question... I'm leaving it in, since it probably has some useful details.
I'd recommend using Json.NET to do this.
If the fact that the json data always has the field named data, then you can write fairly predictable code to output the contents of data into a dictionary.
Off the top of my head, I'd probably go for an anonymous type-based deserialization, kind of like this:
var json = #"{
""data"": {
""Account"": ""150.80"",
""Name"": ""XYZ"",
""Description"": ""Some Value""
}
}";
var schema = new { data = new Dictionary<string, object>()};
var result = JsonConvert.DeserializeAnonymousType(json, schema);
You'd have to reach into result.data to get that dictionary.
You could also just use JObject to pull out the values from data directly, but probably would need to parse that data into a dictionary, so it'd be sort of a double call going on, like this:
var jobj = JObject.Parse(json);
var data = jobj["data"];
var dict = JsonConvert.DeserializeObject<Dictionary<string, object>>
(data.ToString());
There's probably more ways to do this even more efficiently. Like I said, these are just ideas off the top of my head.

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 to deserialize json with a blank field?

I have a json string like this:
[{
"_id": "abcd",
"name": "bender rodriguez",
"meta": {
"location": {}
},
dob": ,
}
]
The section after dob blows up:
return new JavaScriptSerializer().Deserialize<T>(json);
The problem is the empty dob. I cannot seem to find any method to handle something like this. Doesn't even seem to be a common problem? I'm not too familiar with deserializing json, what methods can I use to deal with this other than string.replace(": ,"," : null,")?
The JSON deserialiser you're using is fine, the JSON you're trying to deserialice is wrong, it's missing a value, and the initial double quotes for the dob property.
Use JSONLint to validate JSON.
If that JSON is coming from a component you control, then use a JSON serializer to serialize it properly, if not, you can fix that particular problem using this:
string myJson = "[{ \"_id\": \"abcd\", \"name\": \"bender rodriguez\", \"meta\": { \"location\": {} }, dob\": , } ]";
JavaScriptSerializer().Deserialize(myJson.Replace("dob\": ", "\"dob\": \"\""));
But if the data changes and it keeps having an invalid JSON format, there's little you can do about it but asking whoever did that component to send you valid JSON data.

Categories