So I am trying to deserialize an array from JSON into a C# class using Newtonsoft. I have seen tutorials and other questions on this, but I am running into problems as the array I want to get is not at the top level of the JSON. The JSON is structured like this, where I want to extract the "data" array and deserialize it:
"success": true,
"data": [
{
"key": "americanfootball_nfl",
"active": true,
"group": "American Football",
"details": "US Football",
"title": "NFL",
"has_outrights": false
},
{
"key": "aussierules_afl",
"active": true,
"group": "Aussie Rules",
"details": "Aussie Football",
"title": "AFL",
"has_outrights": false
},
{
"key": "basketball_euroleague",
"active": true,
"group": "Basketball",
"details": "Basketball Euroleague",
"title": "Basketball Euroleague",
"has_outrights": false
}
]}
I know that I first need to extract the data object from the JSON, and then parse that, but I am not too sure how. I have this class to deserialize the JSON:
public class SportsModel
{
public bool Success { get; set; }
public string Data { get; set; }
}
public class SportsData
{
public string Key { get; set; }
public bool Active { get; set; }
public string Group { get; set; }
public string Details { get; set; }
public string Title { get; set; }
public bool HasOutrights { get; set; }
}
And currently get the top level of the data using this:
SportsModel data = JsonConvert.DeserializeObject<SportsModel>(response);
I want to put the JSON array data into a list object, so that I can access it all
You only need to fix this part to make the serializer understand you're deserializing the Data field into a type of SportsData and not a string.
public class SportsModel
{
public bool Success { get; set; }
public List<SportsData> Data { get; set; }
}
Update
To get data into a list, I would assume you are referring to something of this nature
SportsModel result = JsonConvert.DeserializeObject<SportsModel>(response);
var sportsDataList = result.Data;
Your SportModels class needs to be updated to:
public class SportsModel
{
public bool Success { get; set; }
public List<SportsData> Data { get; set; }
}
SportsModel result = JsonConvert.DeserializeObject<SportsModel>(response);
And you will Data in a List.
What you can do is; go to visual studio and in edit menu menu and paste special
and click then paste json as class.
But first you need to copy the json string first.
Related
I have JSON string that came from AWS Lambda:
"body": "{'From': nemesises#live.com, 'To': suhomlin.eugene93#gmail.com}",
And try to deserialize it like this
var email = JsonConvert.DeserializeObject<SendEmailMessage>(emailRequest.Message);
Here is the class to what I need to deserialize
public class SendEmailMessage
{
public string From { get; set; }
public string To { get; set; }
public object Data { get; set; }
public int TemplateId { get; set; }
public List<string> Attachments { get; set; }
}
But I get this error
Newtonsoft.Json.JsonReaderException: Unexpected content while parsing JSON. Path 'From', line 1, position 11.
How I can solve this?
You need to wrap the entire json in {}.
{
"body": "{'From': nemesises#live.com, 'To': suhomlin.eugene93#gmail.com}"
}
You can use a site like https://jsonlint.com/ to work out things like this.
So the problem was in the format of the body
Here the correct format is
{
"Records": [
{
"messageId": "19dd0b57-b21e-4ac1-bd88-01bbb068cb78",
"receiptHandle": "MessageReceiptHandle",
"body": "{ \"Message\":\"{ 'from': 'nemesises#live.com','to': 'suhomlin.eugene93#gmail.com',}\"}",
"attributes": {
"ApproximateReceiveCount": "1",
"SentTimestamp": "1523232000000",
"SenderId": "123456789012",
"ApproximateFirstReceiveTimestamp": "1523232000001"
},
"messageAttributes": {},
"md5OfBody": "7b270e59b47ff90a553787216d55d91d",
"eventSource": "aws:sqs",
"eventSourceARN": "arn:{partition}:sqs:{region}:123456789012:MyQueue",
"awsRegion": "{region}"
}
]
}
I am familiar with JSON.net a bit and can Deserialize the JSON with basic structure (upto one child). I am currently in process of Deserializing the JSON that is returned from Netatmo API. The structure of JSON is complicated for me. Following is the basic structure of the JSON,
_id
place
location
Dynamic Value 1
Dynamic Value2
altitude
timezone
mark
measures
Dynamic Value 1
res
Dynamic Value 1
Dynamic Value 1
Dynamic Value 2
type
Dynamic Value 1
Dynamic Value 2
modules
Dynamic Value 1
Dynamic Value 1 and Dynamic Value 2 represents the values that is changed for each id. The complete JSON is given below,
{
"body": [{
"_id": "70:ee:50:02:b4:8c",
"place": {
"location": [-35.174779762001, -5.8918476117544],
"altitude": 52,
"timezone": "America\/Fortaleza"
},
"mark": 0,
"measures": {
"02:00:00:02:ba:2c": {
"res": {
"1464014579": [16.7, 77]
},
"type": ["temperature", "humidity"]
},
"70:ee:50:02:b4:8c": {
"res": {
"1464014622": [1018.1]
},
"type": ["pressure"]
}
},
"modules": ["02:00:00:02:ba:2c"]
}, {
"_id": "70:ee:50:12:40:cc",
"place": {
"location": [-16.074257294385, 11.135715243973],
"altitude": 14,
"timezone": "Africa\/Bissau"
},
"mark": 14,
"measures": {
"02:00:00:06:7b:c8": {
"res": {
"1464015073": [26.6, 78]
},
"type": ["temperature", "humidity"]
},
"70:ee:50:12:40:cc": {
"res": {
"1464015117": [997]
},
"type": ["pressure"]
}
},
"modules": ["02:00:00:06:7b:c8"]
}],
"status": "ok",
"time_exec": 0.010364055633545,
"time_server": 1464015560
}
I am confused by looking at the complex structure of this JSON. For single level of JSON I have used this code in the past,
IList<lstJsonAttributes> lstSearchResults = new List<lstJsonAttributes>();
foreach (JToken objResult in objResults) {
lstJsonAttributes objSearchResult = JsonConvert.DeserializeObject<lstJsonAttributes>(objResult.ToString());
lstSearchResults.Add(objSearchResult);
}
But for so many child I have yet to understand how the object class will be created. Any guidance will highly appreciated.
Update:
This is what I have achieved so far.
I have created a main class as below,
public class PublicDataClass
{
public string _id { get; set; }
public PublicData_Place place { get; set; }
public string mark { get; set; }
public List<string> modules { get; set; }
}
and "Place" class is as follow,
public class PublicData_Place
{
public List<string> location { get; set; }
public string altitude { get; set; }
public string timezone { get; set; }
}
Then I have Deserialized the object in the following code line,
var obj = JsonConvert.DeserializeObject<List<PublicDataClass>>(jsonString);
I can now successfully get all the data except the "measures" which is little bit more complicated.
Using json.net, JSON objects that have arbitrary property names but fixed schemas for their values can be deserialized as a Dictionary<string, T> for an appropriate type T. See Deserialize a Dictionary for details. Thus your "measures" and "res" objects can be modeled as dictionaries.
You also need a root object to encapsulate your List<PublicDataClass>, since your root JSON container is an object like so: { "body": [{ ... }] }.
Thus you can define your classes as follows:
public class RootObject
{
public List<PublicDataClass> body { get; set; }
public string status { get; set; }
public double time_exec { get; set; }
public int time_server { get; set; }
}
public class PublicDataClass
{
public string _id { get; set; }
public PublicData_Place place { get; set; }
public int mark { get; set; }
public List<string> modules { get; set; }
public Dictionary<string, Measure> measures { get; set; }
}
public class PublicData_Place
{
public List<double> location { get; set; } // Changed from string to double
public double altitude { get; set; } // Changed from string to double
public string timezone { get; set; }
}
public class Measure
{
public Measure()
{
this.Results = new Dictionary<string, List<double>>();
this.Types = new List<string>();
}
[JsonProperty("res")]
public Dictionary<string, List<double>> Results { get; set; }
[JsonProperty("type")]
public List<string> Types { get; set; }
}
Then do
var root = JsonConvert.DeserializeObject<RootObject>(jsonString);
var obj = root.body;
I've worked with XML for a few years and my change to JSON structure I've got a little confused too, always that I want to see how an object look like I use this web site jsoneditoronline Just copy and paste your JSON and click on arrow to parse to an object, I hope it helps until you get used to JSON structure.
I just got my json response as a string.My json is given below,
"code": 0,
"message": "success",
"students": {
"details":{
"hjeke": {
"id": "257633000000070001",
"name": "hjeke",
"percentage": 36,
"type": "Good",
},
"Second": {
"id": "257633000000073001",
"name": "Second",
"percentage": 4,
"type": "bad",
}
}
}
Like hjeke and Second there are many key value pairs,how can i deserialize my json using Newtonsoft.json
Try to understand my solution in your previous question
How to deserialize json data in windows phone?
Your first JSON in that question was good and simple to use.
JSON, where field names are unique not convinient to deserialize. So, you got problems such as public class Hjeke and public class Second for each instance, when you use code generator.
Use JSON-structure with list of students:
"code": 0,
"message": "success",
"students": [
{
"id": "257633000000070001",
"name": "hjeke",
"percentage": 36,
"type": "Good",
},
{
"id": "257633000000073001",
"name": "Second",
"percentage": 4,
"type": "bad",
}]
is good and flexible structure. Using this, you don't need to parse not obvious fields like
"details":{
"hjeke": {
and so on.
And work with them using classes, from my previous answer. The main idea - you need list of objects. public List<StudentDetails> students. Then, all students objects deserialized in List, which is easy to use.
As everybody mentioned your json seems to be very unflexible, huh.
You can extract the data you are interested in.
So this is your model:
public class StudentDetails
{
public string id { get; set; }
public string name { get; set; }
public int percentage { get; set; }
public string type { get; set; }
}
And this is how you can extract it:
var jsonObj = JObject.Parse(str);
// get JSON result objects into a list
var results = jsonObj["students"]["details"].Children().Values();
// serialize JSON results into .NET objects
var details = new List<StudentDetails>();
foreach (JToken result in results)
{
var st = result.ToString();
var searchResult = JsonConvert.DeserializeObject<StudentDetails>(st);
details.Add(searchResult);
}
I'm using a newtonsoft.json library here.
Your Response string has some mistakes man, its not a valid json
just small modification to be done as below:
{
"code": 0,
"message": "success",
"students": {
"details": {
"hjeke": {
"id": "257633000000070001",
"name": "hjeke",
"percentage": 36,
"type": "Good"
},
"Second": {
"id": "257633000000073001",
"name": "Second",
"percentage": 4,
"type": "bad"
}
}
}
}
you can make out the difference
Now Follow these steps:
1.Go to this link Json to C#
2.place your Json string there and generate C# class object
3.Now create this class in your solution
4.Now deserialize As below
var DeserialisedObject = JsonConvert.DeserializeObject<Your Class>(YourJsonString);
First, create the classes:
public class Hjeke
{
public string id { get; set; }
public string name { get; set; }
public int percentage { get; set; }
public string type { get; set; }
}
public class Second
{
public string id { get; set; }
public string name { get; set; }
public int percentage { get; set; }
public string type { get; set; }
}
public class Details
{
public List<Hjeke> hjeke { get; set; }
public List<Second> Second { get; set; }
}
public class Students
{
public List<Details> details { get; set; }
}
public class RootObject
{
public int code { get; set; }
public string message { get; set; }
public List<Students> students { get; set; }
}
After that, use JSON.NET to deserialize:
var deserialized = JsonConvert.DeserializeObject<Class1>(YourStringHere);
Do you have any influence over the json response? Details should probably be a JSONArray in this case, not an object with a varying amount of properties, since I assume that's what you mean is the issue here.
I've been playing with this for the past few days and I'm hoping someone could shed some light on what the issue could be.
I have this custom object that I created:
public class WorldInformation
{
public string ID { get; set; }
public string name { get; set; }
}
and this JSON data:
string world = "[{\"id\":\"1016\",\"name\":\"Sea of Sorrows\"}, {\"id\":\"1008\",\"name\":\"Jade Quarry\"},{\"id\":\"1017\",\"name\":\"Tarnished Coast\"},{\"id\":\"1006\",\"name\":\"Sorrow's Furnace\"},{\"id\":\"2014\",\"name\":\"Gunnar's Hold\"}]";
and I can sucessfully save the data in my custom object by deserializing it:
List<WorldInformation> worlds = JsonConvert.DeserializeObject<List<WorldInformation>>(world);
But...
When I create a custom object like this
public class EventItems
{
public string World_ID { get; set; }
public string Map_ID { get; set; }
public string Event_ID { get; set; }
public string State { get; set; }
}
and have JSON data like this:
string eventItem = "{\"events\":[{\"world_id\":1011,\"map_id\":50,\"event_id\":\"BAD81BA0-60CF-4F3B-A341-57C426085D48\",\"state\":\"Active\"},{\"world_id\":1011,\"map_id\":50,\"event_id\":\"330BE72A-5254-4036-ACB6-7AEED05A521C\",\"state\":\"Active\"},{\"world_id\":1011,\"map_id\":21,\"event_id\":\"0AC71429-406B-4B16-9F2F-9342097A50AD\",\"state\":\"Preparation\"},{\"world_id\":1011,\"map_id\":21,\"event_id\":\"C20D9004-DF6A-4217-BF25-7D6B5788A94C\",\"state\":\"Success\"}]}";
I get an error when I try to deserialize it
List<EventItems> events = JsonConvert.DeserializeObject<List<EventItems>>(eventItem);
The error message I get is:
Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[WebApplication1.EventItems]' 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) 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.
Path 'events', line 1, position 10.
Unforturnately there isn't a way to specify the root Json element like the XmlSerializer.
See How to deserialize JSON array with "root" element for each object in array using Json.NET?
public class EventItems
{
public EventItems()
{
Events = new List<EventItem>();
}
public List<EventItem> Events { get; set; }
}
public class EventItem
{
public string World_ID { get; set; }
public string Map_ID { get; set; }
public string Event_ID { get; set; }
public string State { get; set; }
}
Usage:
string eventItem = "{\"events\":[{\"world_id\":1011,\"map_id\":50,\"event_id\":\"BAD81BA0-60CF-4F3B-A341-57C426085D48\",\"state\":\"Active\"},{\"world_id\":1011,\"map_id\":50,\"event_id\":\"330BE72A-5254-4036-ACB6-7AEED05A521C\",\"state\":\"Active\"},{\"world_id\":1011,\"map_id\":21,\"event_id\":\"0AC71429-406B-4B16-9F2F-9342097A50AD\",\"state\":\"Preparation\"},{\"world_id\":1011,\"map_id\":21,\"event_id\":\"C20D9004-DF6A-4217-BF25-7D6B5788A94C\",\"state\":\"Success\"}]}";
var items = JsonConvert.DeserializeObject<EventItems>(eventItem);
In first case your json is array of objects, so deserialization into a list of your class type succeeds.
In second case, your json is an object, and its "events" property is set to an array of objects, so it cannot be deserialized into a list.
What you may do, is change your class declaration:
public class EventItem
{
public string World_ID { get; set; }
public string Map_ID { get; set; }
public string Event_ID { get; set; }
public string State { get; set; }
}
public class EventItems
{
public EventItem[] Events { get; set; }
}
And deserialize it:
EventItems events = JsonConvert.DeserializeObject<EventItems>(eventItem);
Simply remove the object events from the 2nd JSON string:
string eventItem = "[{\"world_id\":1011,\"map_id\":50,\"event_id\":\"BAD81BA0-60CF-4F3B-A341-57C426085D48\",\"state\":\"Active\"},{\"world_id\":1011,\"map_id\":50,\"event_id\":\"330BE72A-5254-4036-ACB6-7AEED05A521C\",\"state\":\"Active\"},{\"world_id\":1011,\"map_id\":21,\"event_id\":\"0AC71429-406B-4B16-9F2F-9342097A50AD\",\"state\":\"Preparation\"},{\"world_id\":1011,\"map_id\":21,\"event_id\":\"C20D9004-DF6A-4217-BF25-7D6B5788A94C\",\"state\":\"Success\"}]";
It seems that your JSON string is not the same in both examples.
On the first example, you're using a simple JSON array:
[
{
"id": "1016",
"name": "Sea of Sorrows"
},
{
"id": "1008",
"name": "Jade Quarry"
},
{
"id": "1017",
"name": "Tarnished Coast"
},
{
"id": "1006",
"name": "Sorrow's Furnace"
},
{
"id": "2014",
"name": "Gunnar's Hold"
}
]
And on the second example, you're assigning your array to an object (events):
{
"events":
[
{
"world_id": 1011,
"map_id": 50,
"event_id": "BAD81BA0-60CF-4F3B-A341-57C426085D48",
"state": "Active"
},
{
"world_id": 1011,
"map_id": 50,
"event_id": "330BE72A-5254-4036-ACB6-7AEED05A521C",
"state": "Active"
},
{
"world_id": 1011,
"map_id": 21,
"event_id": "0AC71429-406B-4B16-9F2F-9342097A50AD",
"state": "Preparation"
},
{
"world_id": 1011,
"map_id": 21,
"event_id": "C20D9004-DF6A-4217-BF25-7D6B5788A94C",
"state": "Success"
}
]
}
json ="{
"data": [
{
"id": "1000",
"from": {
"name": "Anthony Waema",
"category": "message",
"id": "192"
},
"message": "this is the message",
"updated_time": "2001-05-06T19:34:15+0000",
"likes": {
"data": [
{
"id": "100001692250255",
"name": "\u00dcnal Turanl\u0131"
},
{
"id": "100001060078996",
"name": "S\u00e9f\u00e2 K\u00e2ql\u00e4Nn"
}]
},
{
"id": "10150186255753553",
"from": {
"name": "another name",
"category": "message",
"id": "100001"
},
"message": "this is the message",
"updated_time": "2001-04-06T19:34:15+0000",
"likes": {
"data": [
{
"id": "1002345",
"name": "\u00dcnal Turanl\u0131"
},
{
"id": "100234",
"name": "S\u00e9f\u00e2 K\u00e2ql\u00e4Nn"
}]
}
}
]
}";
public class Allstatus
{
public List<sdata> data { get; set; }
public scpaging paging { get; set; }
}
public class sdata
{
public string id { get; set; }
public sfrom from { get; set; }
public string message { get; set; }
public string updated_time {get; set;}
public List<likesdata> likes { get; set; }
}
public class likesdata
{
public string id{ get; set; }
public string name{ get; set; }
}
public class sfrom
{
public string name {get; set;}
public string category {get; set;}
public string id {get; set;}
}
JavaScriptSerializer ser = new JavaScriptSerializer();
page = ser.Deserialize<allstatus>(json);
foreach (sdata cd in page.data)
{
foreach(likesdata ld in cd.likes.data)
{
Console.WriteLine(ld.id+"\t"+ld.name);
}
}
problem:
I need to parse the json and retrieve likes data.
I can access "from" data but not "likes" data.. I get nullreference error when I do this. help needed here.. Thanks.
Edit2:
Referring https://gist.github.com/973510, its clear from the returned json, that if a particular facebook message doesnt have any likes, then the returned json doesnt contain a property called likes. Hence likes property of sdata object is null. Thats just how the server returns the data.
There are two ways you can deal with this. Either do a manual check whether likes is null. Or initialize the likes property in the sdata constructor. And initialize the likesdata list in the likesdatacollection constructor.
Code:
public class sdata
{
// other properties
public likedatacollection likes { get; set; }
public sdata()
{
likes = new likedatacollection();
}
}
public class likedatacollection
{
public List<likesdata> data { get; set; }
public likedatacollection()
{
data = new List<likesdata>();
}
}
This way, even if fb doesnt return any likes, the constructors will initialize the properties, so they will not be null. You can then check whether likes.data.Count > 0. If yes, then fb returned likes, else fb didnt return likes.
Edit1:
From the OP's comment, its clear that the json is properly formed. Meaning, the json is as retrieved from some server api. Therefore it is the sdata class that is the culprit. Please look at this gist for the full solution.
The short version. For the simplest case, your c# classes need to follow the exact same structure as your json. As per the json, data has a property called likes. the likes object has a property called data which is an array of objects with properties id and name.
So your c# class sdata should have a property called likes of type likesdatacollection. This class should have a property data of type List<likesdata>...
Off topic, people generally seem to prefer Json.Net ... so you may want to use that. The reason I use it is because I need it to work in a .Net 2.0 code base ...
You should try running your JSON through a validator like JSON Lint. That should help you find any JSON errors.