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?!
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)
This question already has answers here:
Deserializing JSON when sometimes array and sometimes object
(7 answers)
Closed 2 years ago.
I got a JSON data like below and the FlightSegment object type seems one of the Array and the other one is not.
When I create an object as FlightSegment[], i am getting this error :
Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'WA_2_0_RS.FlightSegment[]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List<T>) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.
What it should be as c# class?
{
"FlightSegment": {
"DepartureAirport": {
"LocationCode": "ESB"
},
"Ticket": "eTicket",
"ArrivalAirport": {
"LocationCode": "ADB"
},
"DateChangeNbr": false,
"StopQuantity": "0",
"CodeshareInd": false,
"Equipment": {
"Value": "UNKNOWN_PLANE",
"AirEquipType": "***"
},
"DepartureDateTime": "2020-12-22T20:10:00.000+03:00",
"ArrivalDateTime": "2020-12-22T21:30:00.000+03:00",
"FlightNumber": "****",
"OperatingAirline": {
"CompanyShortName": "**"
},
"JourneyDuration": "P0DT1H20M0.000S"
}
}, {
"FlightSegment": [{
"DepartureAirport": {
"LocationCode": "ESB"
},
"Ticket": "eTicket",
"ArrivalAirport": {
"LocationCode": "SAW"
},
"DateChangeNbr": false,
"StopQuantity": "0",
"GroundDuration": "P0DT0H45M0.000S",
"CodeshareInd": false,
"Equipment": {
"Value": "A320-200",
"AirEquipType": "320"
},
"DepartureDateTime": "2020-12-22T12:05:00.000+03:00",
"ArrivalDateTime": "2020-12-22T13:10:00.000+03:00",
"FlightNumber": "****",
"OperatingAirline": {
"CompanyShortName": "**"
},
"JourneyDuration": "P0DT1H5M0.000S"
}, {
"DepartureAirport": {
"LocationCode": "SAW"
},
"Ticket": "eTicket",
"ArrivalAirport": {
"LocationCode": "ADB"
},
"DateChangeNbr": false,
"StopQuantity": "0",
"CodeshareInd": false,
"Equipment": {
"Value": "UNKNOWN_PLANE",
"AirEquipType": "73D"
},
"DepartureDateTime": "2020-12-22T13:55:00.000+03:00",
"ArrivalDateTime": "2020-12-22T15:00:00.000+03:00",
"FlightNumber": "****",
"OperatingAirline": {
"CompanyShortName": "**"
},
"JourneyDuration": "P0DT1H5M0.000S"
}
]
}
#Caius Jard's solution has fixed my issue.
Solution
I receive a GET request response from a REST API, in a string. As received, it looks like this:
[
{\"passport_expiration\": \"2019-09-14\", \"first_name\": \"asdfasdf\", \"last_name\": \"asdfasdf\", \"cass_status\": \"APPROVED\", \"notes\": null, \"kcm_status\": \"DENIED\", \"employment_type\": \"flight_deck\", \"employee_id\": \"10556\", \"passport_id\": \"12341234\"},
{\"passport_expiration\": \"2026-01-04\", \"first_name\": \"asdfasdf\", \"last_name\": \"asdfasdf\", \"cass_status\": \"APPROVED\", \"notes\": null, \"kcm_status\": \"DENIED\", \"employment_type\": \"flight_deck\", \"employee_id\": \"10557\", \"passport_id\": \"12341234\"},
{\"passport_expiration\": \"2026-08-31\", \"first_name\": \"asdfasdf\", \"last_name\": \"MC asdfasdf\", \"cass_status\": \"APPROVED\", \"notes\": null, \"kcm_status\": \"DENIED\", \"employment_type\": \"flight_deck\", \"employee_id\": \"10598\", \"passport_id\": \"12341234\"}
]
When I deserialize this into a dynamic:
dynamic dsCrew = JsonConvert.DeserializeObject(responseText);
dsCrew contains this:
{[
{
"passport_expiration": "2026-08-31",
"first_name": "asdfasdf",
"last_name": "MC asdfasdf",
"cass_status": "APPROVED",
"notes": null,
"kcm_status": "DENIED",
"employment_type": "flight_deck",
"employee_id": "10598",
"passport_id": "12341234"
},
{
"passport_expiration": "2026-11-16",
"first_name": "asdfasdf",
"last_name": "BLasdf",
"cass_status": "APPROVED",
"notes": null,
"kcm_status": "DENIED",
"employment_type": "flight_deck",
"employee_id": "14798",
"passport_id": "12341234"
},
{
"passport_expiration": "2025-05-05",
"first_name": "sadfasdf",
"last_name": "asdf",
"cass_status": "APPROVED",
"notes": "",
"kcm_status": "DENIED",
"employment_type": "flight_deck",
"employee_id": "14838",
"passport_id": "12341234"
}
]}
It seems to have simply removed the escape characters, converted some nulls to Empty Strings, and wrapped the whole thing in an additional set of curly braces. It's like it deserialised into just a different serialized format.
In other SO questions, answers have suggested creating a class to deserialise into:
Deserialised_Crew dsCrew = JsonConvert.DeserializeObject<Deserialised_Crew>(responseText);
But when I do that I get an exception:
"Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'CASS_KCM_Update.Deserialised_Crew' because the type requires a JSON object (e.g. {\"name\":\"value\"}) to deserialize correctly.
JsonConvert.DeserializeObject() doesn't seem to think the responseText is valid JSON. JSONLint.com says the JSON is valid.
I need a way to reference specific pieces of data:
dsCrew[0].last_name seems to reference the entire text inside the square brackets. And I can't find any way to reference with any more specificity than that. dsCrew[0][1].last_name won't work. dsCrew[0](1).last_name is right out.
I need a way to reference the names and employee_id's in this response. I'm relatively new to JSON.
The first issue is probably just what you see in the debugger. That code should be fine.
Your second problem just involves deserializing to an array, since the JSON object is an array of crew:
Deserialised_Crew[] dsCrew = JsonConvert.DeserializeObject<Deserialised_Crew[]>(responseText);
From there on, your code dsCrew[0].last_name should work as expected.
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
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>;