I have a Json string containing arrays and a single key with a value as you can see below.
{
"MSG": "Hallo Stackoverflow!",
"0": {
"ID": "2",
"Subject": "Danish",
"Message": "Message",
"DateEnd": "2016-02-28 00:00:00"
},
"1": {
"ID": "2",
"Subject": "Math",
"Message": "Message",
"DateEnd": "2016-02-29 00:00:00"
}}
I pass this to a JObject to get the MSG value, then remove it from the json. However, when key is gone, the numbers of the array gets deleted and I cannot pass it through my code:
JObject data = JObject.Parse(json);
string MSG = data["MSG"].ToString();
data.Remove("MSG");
List<HomeWork> homework = JsonConvert.DeserializeObject<List<HomeWork>>(json);
I get an error:
Newtonsoft.Json.JsonSerializationException: Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[Memento.HomeWork]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
If I generate it as an array without the key, it works fine.
You are actually trying to deserialize a JSON object rather than a JSON array.
Note that the following would be a JSON array (and you would be able to deserialize it into a List<Homework>):
[{
"ID": "2",
"Subject": "Danish",
"Message": "Message",
"DateEnd": "2016-02-28 00:00:00"
},
{
"ID": "2",
"Subject": "Math",
"Message": "Message",
"DateEnd": "2016-02-29 00:00:00"
}]
In order to deserialize this JSON object, you must use a Dictionary<TKey, TValue> (because you don't know the object's keys beforehand), which in your case is Dictionary<int, Homework>:
Dictionary<int, Homework> homeworks = JsonConvert.DeserializeObject<Dictionary<int, Homework>>(json);
Homework hw = homeworks[0]; //This will be your first homework, the one with ID = 2
Related
I have a JSON below:
{
"value": [
{
"name": "504896c031d2fcb9",
"location": "North Europe",
"properties": {
"state": "UNKNOWN",
"name": "504896c031d2fcb9",
"siteInstanceName": "504896c031d2fcb93ec",
"healthCheckUrl": null,
"machineName": "lw0s",
"containers": null
}
},
{
"name": "35aafa",
"location": "North Europe",
"properties": {
"state": "UNKNOWN",
"name": "35aafae",
"siteInstanceName": "35aafaeff",
"healthCheckUrl": null,
"machineName": "lw1s",
"containers": null
}
}
],
"nextLink": null,
"id": null
}
I have converted JSON to a dynamic as mentioned below:
string kq = reader.ReadToEnd();
dynamic jss = JsonConvert.DeserializeObject(kq);
I want to know how to count how many values in C#? The above example has 2 values.
Thank you.
if you know the key you can do something like
dynamic jss = JsonConvert.DeserializeObject(kq);
jss["value"].Count
Cast as JArray and .Count.
Perhaps, if the value is not an array type, casted array will return as null.
You may add handling to check whether it is not null and get .Count.
dynamic jss = JsonConvert.DeserializeObject(kq);
JArray array = jss["value"] as JArray;
Console.WriteLine(array != null ? array.Count : 0);
Sample program (JsonConvert.DeserializeObject)
Recommendation:
Since you are deserializing JSON string to dynamic, with JsonConvert.DeserializeObject it will return the value of JObject type.
I would suggest using JObject.Parse rather than JsonConvert.DeserializeObject<T> (which is designed for converting to strongly-type object).
You may read this question: JObject.Parse vs JsonConvert.DeserializeObject for more info.
using Newtonsoft.Json.Linq;
JObject jss = JObject.Parse(json);
JArray array = jss["value"] as JArray;
Console.WriteLine(array != null ? array.Count : 0);
Sample program (JObject.Parse)
I'm deserialising a Newtonsoft JArray to a .NET DataTable using:
DataTable dt = (DataTable)JsonConvert.DeserializeObject(dataSet.ToString(), typeof(DataTable));
Where dataSet is a JArray of the basic array format:
{
"dataset": [
{
"periodDesc": "2020",
"cstCode": "",
"CIFValue": null
},
{
"periodDesc": "2017",
"cstCode": "",
"CIFValue": null
},
...
]
}
I get this dataset from an API call via a JObject and it works fine:
JObject jObject = GetJsonFromWebRequest(url);
JArray jArray = (JArray)jObject["dataset"];
Now to do some testing, I took the json response from the GetJsonFromWebRequest and saved it to a .json file.
I also did the same with the JArray when I encountered problems; Whether I use the whole response and parse to a JObject first, or whether I use the subset JArray, when I load this data from file, it just doesn't work! I get the error:
"Cannot deserialize the current JSON array (e.g. [1,2,3]) into type
'System.Data.DataTable' because the type requires a JSON object (e.g.
{"name":"value"}) to deserialize correctly.\r\nTo fix this error
either change the JSON to a JSON object (e.g. {"name":"value"}) or
change the deserialized type to an array or a type that implements a
collection interface (e.g. ICollection, IList) like List that can
be deserialized from a JSON array. JsonArrayAttribute can also be
added to the type to force it to deserialize from a JSON
array."
I'm assuming this might have something to do with linebreaks or something, or how I've saved it as .JSON instead of .TXT maybe?! But I have no idea what is going on - looking at the objects while debugging they seem absolutely identical and it is successfully parsing the JArray as a JArray - it's just the Deserialize bit that fails.
Any idea what's going on here?!
Here are the contents of the file I'm loading from minus the help URL - the mock response:
{
"validation": {
"status": {
"name": "Ok",
"value": 0,
"category": 0,
"description": "",
"helpUrl": "For more reference visit"
},
"message": null,
"count": {
"value": 5,
"started": "2021-09-15T09:14:05.277794+02:00",
"finished": "2021-09-15T09:14:07.8662927+02:00",
"durationSeconds": 2.5884986999999997
},
"datasetTimer": {
"started": "2021-09-15T09:14:05.277794+02:00",
"finished": "2021-09-15T09:14:15.2487336+02:00",
"durationSeconds": 9.9709396
}
},
"dataset": [
{
"periodDesc": "2017",
"cstCode": "",
"CIFValue": null
},
{
"periodDesc": "2018",
"cstCode": "",
"CIFValue": null
},
{
"periodDesc": "2019",
"cstCode": "",
"CIFValue": null
},
{
"periodDesc": "2020",
"cstCode": "",
"CIFValue": null
}
]
}
Ok, this was something to do with NewtonSoft version incompatibility. I needed to explicitly install NewtonSoft 3.x in my NUnit test project and it works fine.
While the main API project doesn't have this package dependency / reference, it did have a line in the startup:
services.AddControllers().AddNewtonsoftJson();
Which apparently does the same thing?!
I have a JSON like this
{
"Customer": {
"$type": "Dictionary`2",
"Id": "6448DE37E2F3D9588118A1950"
},
"Databases": [
{
"$type": "Pime",
"Id": 1,
"Name": "Peter",
"MobNo": 78877629,
"PAN": "SAKKJKJ",
"Defaulter": true,
},
{
"$type": "Pime",
"Id": 2,
"Name": "James",
"MobNo": 58277699,
"PAN": "NAQKJKJ",
"Defaulter": false,
},
{
"$type": "Pime",
"Id": 3,
"Name": "Norton",
"MobNo": 38877699,
"PAN": "TAKKJKJ",
"Defaulter": true,
},
]
}
I'm using a token to select the node and return the customer information whose Id=2
My code goes like this:
StreamReader r = new StreamReader("C:\TestJson\Test.db");
string json = r.ReadToEnd();
JObject o = JObject.Parse(json);
JToken result = o.SelectToken("$.Databases[?(#.Id == '2')]");
But I am getting the result as null. Am I using the wrong token in the SelectToken() method?
First of all given JSON is invalid, in database array value of Name and PAN keys should be of type string. You are missing "(double qoutes) in above json.
Second and most important thing, type of Id is an integer and in your Json Path you are trying to search with string type i.e '2', try to search Id by integer without quoute it will work.
//No single qoutes for 2.
JToken result = o.SelectToken("$.Databases[?(#.Id == 2)]");
I am learning C# and I am trying to parse json/xml responses and check each and every key and value pair. For xml I am converting to json so I have only one function/script to work with both cases. My issue is that I am working with a wide range of json responses which are not similar and there may be arrays in some of the json response. I have tried accessing the "Count" of the json object as a way to check for arrays.
Note: The responses will vary. This example is for Products > Product > name, quantity and category. The next response will change and can be like Country > State > Cities and so on. I cannot rely on creating classes since all responses are going to be different. Plus I am working on automating it so it should be able to handle anything thrown at it.
Sample Json I am working with:
{
"products": {
"product": [
{
"name": "Dom quixote de La Mancha",
"quantity": "12",
"category": "Book"
},
{
"name": "Hamlet",
"quantity": "3",
"category": "Book"
},
{
"name": "War and Peace",
"quantity": "7",
"category": "Book"
},
{
"name": "Moby Dick",
"quantity": "14",
"category": "Book"
},
{
"name": "Forrest Gump",
"quantity": "16",
"category": "DVD"
}
]
}
The way I am accessing the count, name and value is as follows:
dynamic dyn = JsonConvert.DeserializeObject<dynamic>(jsonText);
foreach (JProperty property in dyn.Properties())
{
string propname = property.Name;
var propvalue = property.Value;
int count = property.Count;
}
Is there a way to access these without going through the foreach loop like int count = dyn.Count ? All I am getting from this is null instead of actual values.
For the above example my end result will be like:
This responses contains products> product> 5 x (name, quantity, category)
The QuickWatch for the object:
QuickWatch for dyn object
Try to deserialize your JSON into JObject like below:
var jObject = JsonConvert.DeserializeObject<JObject>(jsonText);
i have an object that is being passed to me from a json obj, each time it is has different feilds, i am using json.net to parse it, it is parsing it correctly and it is putting it in a list of obj
the format after serialization is:
{
"language": "EN",
"code": "test",
"name": "test",
"value": "TEST",
"id": "2222222222222222"
}
the fields are dynamic it can be up to 50 not just 5
any idea on how to parse it??
If you know the items in above format. you could create an typed object. and then you can use DataContractJsonSerializer like below.
DataContractJsonSerializer obj = new DataContractJsonSerializer(typeof(List<Student>));
List<Student> result = obj.ReadObject(stream) as List<myClass>;