What is the right C# structure to deserialize this json into? - c#

I am getting json back from an http and I am trying to deserialized it into a C# object and it keeps coming back as null so my guess is that my data structure is off. Here is my code:
results = httpClient.GetStringAsync(url).Result;
var restResponse = new RestSharp.RestResponse();
restResponse.Content = results;
var deserializer = new JsonDeserializer();
var page = _deserializer.Deserialize<Tree>(restResponse);
Here is the Json:
{
"page":{
"results":[
{
"id":"144111690",
"type":"page",
"status":"current",
"title":"Title 1"
},
{
"id":"157540319",
"type":"page",
"status":"current",
"title":"Title 2"
},
{
"id":"144082624",
"type":"page",
"status":"current",
"title":"Title 3"
}
],
"start":0,
"limit":25,
"size":14
}
}
and Here are my C# objects:
public class Tree
{
public Results page { get; set; }
}
public class Results
{
public ResultDetails results { get; set; }
}
public class ResultDetails
{
public List<PageInfo> Pages { get; set; }
}
public class PageInfo
{
public long id { get; set; }
public string type { get; set; }
public string status { get; set; }
public string title { get; set; }
}
Can anyone advise on what is not "lining up" here?

Why don't you directly create class structure by using Visual studio ..that will give you class structure matching with your json.
you can check here how to generate : Visual Studio Generate Class From JSON or XML
Copy you json >> visual studio Edit menu > Paste Special >> Paste Json as class

This will work:
public class Tree
{
public Page page { get; set; }
}
public class Page
{
public List<Result> results { get; set; }
public int start { get; set; }
public int limit { get; set; }
public int size { get; set; }
}
public class Result
{
public string id { get; set; }
public string type { get; set; }
public string status { get; set; }
public string title { get; set; }
}
results is an array in JSON, but you defined it as an object (ResultDetails)

This might do the trick for you
public class Rootobject
{
[JsonProperty("page")]
public Page page { get; set; }
}
public class Page
{
[JsonProperty("results")]
public Result[] results { get; set; }
[JsonProperty("start")]
public int start { get; set; }
[JsonProperty("limit")]
public int limit { get; set; }
[JsonProperty("size")]
public int size { get; set; }
}
public class Result
{
[JsonProperty("id")]
public string id { get; set; }
[JsonProperty("type")]
public string type { get; set; }
[JsonProperty("status")]
public string status { get; set; }
[JsonProperty("title")]
public string title { get; set; }
}
And the implementation should be
results = httpClient.GetStringAsync(url).Result;
var restResponse = new RestSharp.RestResponse();
restResponse.Content = results;
var deserializer = new JsonDeserializer();
var page = _deserializer.Deserialize<Rootobject>(restResponse);

Related

Deserialize nested JSON, C# [duplicate]

This question already has an answer here:
Deserialize Nested JSON
(1 answer)
Closed 1 year ago.
I need to deserialize some JSON with this format:
{
"message": {
"header": {
"status_code": 200,
"execute_time": 0.29062294960022,
"available": 10000
},
"body": {
"track_list": [
{
"track": {
"track_id": 45085706,
"track_name": "Love Overdose (Deboa & Hannah Holland Remix)",
"primary_genres": {
"music_genre_list": [
{
"music_genre": {
"music_genre_name": "Dance"
}
}
]
}
}
}
]
}
}
}
I have these classes which I got from online generator, so I assume they are ok.
public class Header
{
public int status_code { get; set; }
public double execute_time { get; set; }
public int available { get; set; }
}
public class MusicGenre
{
public int music_genre_id { get; set; }
public int music_genre_parent_id { get; set; }
public string music_genre_name { get; set; }
public string music_genre_name_extended { get; set; }
public string music_genre_vanity { get; set; }
}
public class MusicGenreList
{
public MusicGenre music_genre { get; set; }
}
public class PrimaryGenres
{
public List<MusicGenreList> music_genre_list { get; set; }
}
public class Track
{
public int track_id { get; set; }
public string track_name { get; set; }
public List<object> track_name_translation_list { get; set; }
public int track_rating { get; set; }
public int commontrack_id { get; set; }
public int instrumental { get; set; }
public int #explicit { get; set; }
public int has_lyrics { get; set; }
public int has_subtitles { get; set; }
public int has_richsync { get; set; }
public int num_favourite { get; set; }
public int album_id { get; set; }
public string album_name { get; set; }
public int artist_id { get; set; }
public string artist_name { get; set; }
public string track_share_url { get; set; }
public string track_edit_url { get; set; }
public int restricted { get; set; }
public DateTime updated_time { get; set; }
public PrimaryGenres primary_genres { get; set; }
}
public class TrackList
{
public Track track { get; set; }
}
public class Body
{
public List<TrackList> TrackList { get; set; }
}
public class Message
{
public Header header { get; set; }
public Body body { get; set; }
}
public class Root
{
public Message message { get; set; }
}
I tried to deserialize the JSON with this code:
using (StreamReader r = new StreamReader(#"c:\users\xxxx\desktop\1.json"))
{
string json = r.ReadToEnd();
var tracks = JsonConvert.DeserializeObject<Track>(json);
}
but I got nothing. I'm new to this; made it with simpler JSON, but I can't figure out how to do it with this code. I want to print a list with just the song names.
If anyone can help me I would appreciate it!
There are a couple of problems here:
In your Body class, the TrackList property does not match the JSON. The corresponding property in the JSON is called track_list. The class properties must either exactly match the JSON (ignoring case) or else you need to use a [JsonProperty] attribute on the property to indicate what the JSON name will be. For example:
public class Body
{
[JsonProperty("track_list")]
public List<TrackList> TrackList { get; set; }
}
You are attempting to deserialize into the Track class, but you should be deserializing to Root since that represents the root of the JSON.
var root = JsonConvert.DeserializeObject<Root>(json);
Once you have deserialized to Root you can "drill down" to print out the tracks.
foreach (var item in root.message.body.TrackList)
{
Console.WriteLine(item.track.track_name);
}
Fiddle: https://dotnetfiddle.net/JnljGU

c# Parsing json to object

I need some help to parse the json rest from IsThereASale API to a c# object but I got stuck because of the json layout:
https://del.dog/orfelefane.json
What I need here is the info from the data array.
Here is how i get the json response:
var client = new RestClient("https://api.isthereanydeal.com/");
client.UseNewtonsoftJson();
var request = new RestRequest("https://api.isthereanydeal.com/v01/deals/list/?key=" + Config.apiKey + "&sort=time");
var json = JsonConvert.DeserializeObject<Dictionary<string, string>>(response.Content);
As you can notice above I've tried to convert it to a dictionary, but with no success.
You can use online converter for this
public partial class Orfelefane
{
public Meta Meta { get; set; }
public Data Data { get; set; }
}
public partial class Data
{
public long Count { get; set; }
public List<List> List { get; set; }
public DataUrls Urls { get; set; }
}
public partial class List
{
public string Plain { get; set; }
public string Title { get; set; }
public double PriceNew { get; set; }
public double PriceOld { get; set; }
public long PriceCut { get; set; }
public long Added { get; set; }
public long? Expiry { get; set; }
public Shop Shop { get; set; }
public List<Drm> Drm { get; set; }
public ListUrls Urls { get; set; }
}
public partial class Shop
{
public Id Id { get; set; }
public Name Name { get; set; }
}
public partial class ListUrls
{
public Uri Buy { get; set; }
public Uri Game { get; set; }
}
public partial class DataUrls
{
public Uri Deals { get; set; }
}
public partial class Meta
{
public string Currency { get; set; }
}
public enum Drm { DrmFree, Steam };
public enum Id { Bundlestars, Gog, Itchio, Steam };
public enum Name { Fanatical, Gog, ItchIo, Steam };
lastly
var json = JsonConvert.DeserializeObject<Orfelefane>(response.Content);
EDIT:
If your json is not stronglytyped, I suggest you to use
var json = JsonConvert.DeserializeObject<dynamic>(response.Content);
If only the specific part of your json is not static then you can replace that part with dynamic
let say that the content of the List is dynamic inside data, then change
public partial class Data
{
public long Count { get; set; }
public List<List> List { get; set; }
public DataUrls Urls { get; set; }
}
to
public partial class Data
{
public long Count { get; set; }
//OR public dynamic List {get; set;}
public List<dynamic> List { get; set; }
public DataUrls Urls { get; set; }
}

How to read sections of JSON document?

I have a JSON document and I want to access the details of the STATUS SECTION but it keeps returning null.
JSON Data is as shown:
{
"results":[
{
"messageId":"15712480583306574",
"to":"",
"from":"TestServer",
"sentAt":"2019-10-16T17:47:38.368+0000",
"doneAt":"2019-10-16T17:47:38.370+0000",
"smsCount":1,
"mccMnc":"null",
"price":{
"pricePerMessage":0.0,
"currency":"USD"
},
"status":{
"groupId":5,
"groupName":"REJECTED",
"id":8,
"name":"REJECTED_PREFIX_MISSING",
"description":"Number prefix missing"
},
"error":{
"groupId":0,
"groupName":"OK",
"id":0,
"name":"NO_ERROR",
"description":"No Error",
"permanent":false
}
}
]
}
C# Code is:
string JsonData = response.Content.ToString();
dynamic results = JsonConvert.DeserializeObject<dynamic>(JsonData);
var statuses = results.status;
foreach(var stat in statuses) {
string groupname = stat.groupName.Value;
string name = stat.name.Value;
string description = stat.description.Value;
}
It keeps returning null, How can I access these members? I am using Newtonsoft.
If you want to access the status object property you need to rewrite your whole code.
string JsonData = response.Content.ToString();
var input = JObject.Parse(str);
var results = input["results"].Children();
var status = results.First()["status"];
string groupname = status["groupName"].ToString();
string name = status["name"].ToString();
string description = status["description"].ToString();
Console.WriteLine(groupname);
Console.WriteLine(name);
Console.WriteLine(description);
The result in Console
REJECTED
REJECTED_PREFIX_MISSING
Number prefix missing
But I would rather use concrete class. You need to create multiple classes. Here is good example.
public class Envelope
{
public List<Item> Results { get; set; }
}
public class Item
{
public Status Status { get; set; }
}
public class Status
{
public int GroupId { get; set; }
public string GroupName { get; set; }
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
After that the usage is much simpler.
string JsonData = response.Content.ToString();
MyEnvelope envelope = JsonConvert.DeserializeObject<MyEnvelope>(JsonData);
var status = envelope.results[0].status;
Console.WriteLine(status.GroupName);
Console.WriteLine(status.Name);
Console.WriteLine(status.Description);
Finest Option: Create A model for the JSON.
public class Price
{
public double pricePerMessage { get; set; }
public string currency { get; set; }
}
public class Status
{
public int groupId { get; set; }
public string groupName { get; set; }
public int id { get; set; }
public string name { get; set; }
public string description { get; set; }
}
public class Error
{
public int groupId { get; set; }
public string groupName { get; set; }
public int id { get; set; }
public string name { get; set; }
public string description { get; set; }
public bool permanent { get; set; }
}
public class Result
{
public string messageId { get; set; }
public string to { get; set; }
public string from { get; set; }
public DateTime sentAt { get; set; }
public DateTime doneAt { get; set; }
public int smsCount { get; set; }
public string mccMnc { get; set; }
public Price price { get; set; }
public Status status { get; set; }
public Error error { get; set; }
}
public class RootObject
{
public List<Result> results { get; set; }
}
Then do RootObject results = JsonConvert.DeserializeObject<RootObject>(JsonData);
Fair Option: Get the exact JToken you want.
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json.Linq;
public class Program
{
public static void Main()
{
string jsonData = "{\"results\":[{\"messageId\":\"15712480583306574\",\"to\":\"\",\"from\":\"TestServer\",\"sentAt\":\"2019-10-16T17:47:38.368+0000\",\"doneAt\":\"2019-10-16T17:47:38.370+0000\",\"smsCount\":1,\"mccMnc\":\"null\",\"price\":{\"pricePerMessage\":0.0,\"currency\":\"USD\"},\"status\":{\"groupId\":5,\"groupName\":\"REJECTED\",\"id\":8,\"name\":\"REJECTED_PREFIX_MISSING\",\"description\":\"Number prefix missing\"},\"error\":{\"groupId\":0,\"groupName\":\"OK\",\"id\":0,\"name\":\"NO_ERROR\",\"description\":\"No Error\",\"permanent\":false}}]}";
JObject jObject = JObject.Parse(jsonData);
Console.WriteLine(jObject.SelectToken("results[0].status"));
}
}

Deserializing a nested JSON string, cannot access properties

I am having issues deserializing a nested JSON array from the Genius lyric website API. I formulated the object using http://json2csharp.com. When I deserialize the object, I am unable to access the properties inside of the class, which wasn't entirely unexpected, I am just not sure how to properly design an actual solution to the problem. The JSON object conversions work fine when they are not nested.
What would be the best way to go about handling this?
Here is the conversion code:
string test = await G.SearchGeniusASync(textBox1.Text);
var data = JsonConvert.DeserializeObject<GeniusApiObject>(test);
Here is my class:
class GeniusApiObject
{
public class Meta
{
public int status { get; set; }
}
public class Stats
{
public bool hot { get; set; }
public int unreviewed_annotations { get; set; }
public int concurrents { get; set; }
public int pageviews { get; set; }
}
public class PrimaryArtist
{
public string api_path { get; set; }
public string header_image_url { get; set; }
public int id { get; set; }
public string image_url { get; set; }
public bool is_meme_verified { get; set; }
public bool is_verified { get; set; }
public string name { get; set; }
public string url { get; set; }
public int iq { get; set; }
}
public class Result
{
public int annotation_count { get; set; }
public string api_path { get; set; }
public string full_title { get; set; }
public string header_image_thumbnail_url { get; set; }
public string header_image_url { get; set; }
public int id { get; set; }
public int lyrics_owner_id { get; set; }
public string lyrics_state { get; set; }
public string path { get; set; }
public int? pyongs_count { get; set; }
public string song_art_image_thumbnail_url { get; set; }
public Stats stats { get; set; }
public string title { get; set; }
public string title_with_featured { get; set; }
public string url { get; set; }
public PrimaryArtist primary_artist { get; set; }
}
public class Hit
{
public List<object> highlights { get; set; }
public string index { get; set; }
public string type { get; set; }
public Result result { get; set; }
}
public class Response
{
public List<Hit> hits { get; set; }
}
public class RootObject
{
public Meta meta { get; set; }
public Response response { get; set; }
}
}
This is the source for the SearchGeniusASync method in case it is helpful:
public async Task<string>SearchGeniusASync(string searchParameter)
{
httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", clientAccessToken);
var result = await httpClient.GetAsync(new Uri("https://api.genius.com/search?q=" + searchParameter), HttpCompletionOption.ResponseContentRead);
var data = await result.Content.ReadAsStringAsync();
return data;
}
This is the scope I am given access to:
https://i.imgur.com/9mZMvfp.png
Here's a sample JSON request in plaintext:
https://pastebin.com/iA8dQafW
GeniusApiObject is not needed in the code, but I'll leave it in just because it helps organize things (may be that something else also has a RootObject from the auto-generator).
The problem is that you are trying to deserialize to what is just an empty class, the class itself has no properties, so you can't deserialize to it. You need to deserialize to the GeniusApiObject.RootObject.
var data = JsonConvert.DeserializeObject<GeniusApiObject.RootObject>(test);
Will deserialize to the .RootObject subclass. This is verified working:
Where I'm using File.ReadAllText("test.json") to load the example API data provided.
Here is a .NET Fiddle showing it working (without the root object and only one song in the response). Thanks to #maccttura.

JSON.NET Resolving Nested Data Types

I'm new to JSON.NET, and I've been playing with the new Marvel API that was recently released.
When I call this API it will return the following JSON Data Structure:-
{
"code": 200,
"status": "Ok",
"etag": "f0fbae65eb2f8f28bdeea0a29be8749a4e67acb3",
"data":
{
"offset": 0,
"limit": 20,
"total": 30920,
"count": 20,
"results": [{array of objects}}]
}
}
I can create Classes for this Data like this :
public class Rootobject
{
public int code { get; set; }
public string status { get; set; }
public string etag { get; set; }
public Data data { get; set; }
}
public class Data
{
public int offset { get; set; }
public int limit { get; set; }
public int total { get; set; }
public int count { get; set; }
public Result[] results { get; set; }
}
public class Result
{
}
Now, my issue. The Results that come back from the API can relate to different Objects, it could be results relating to Characters, Comics, Series etc. The objects all hold different properties.
I need to be able to swap out the Result Class properties based on the Entity Type that the results relate too?
Can this actually be done?
You can use var jObj = JObject.Parse(jsonString) then discover what object type it is by which properties are available on the object.
jObj["someComicSpecificProperty"] != null
However this is not full proof and will need to be done on a per object basis for the results array.
An alternate approach I have seen people use is to have a property on the object that is "typeName".
However the root cause of this problem is that you are trying to strongly type a property that is not strongly typed. I would really recommend splitting these different types of results out into different properties so that you don't have this problem.
As promised, I've posted the anser to this problem. It turns out that the JSON response has nested data covering all related data-types, very much like a relational database.
I found something really cool, I basically made a request to the API and converted its response to a string. I then used the debugger to take a copy of the contents to the clipboard.
I created a new Class and Called it MarvelResponse.
I added the NewtonSoft.Json directive to the file, and used the Paste Special option from Edit Menu in VS2012. Here you can paste the option "Paste as JSON CLasses".
After some minor tweaking here is what it provided :-
namespace Kaiser.Training.Data.JSONClasses
{
public class MarvelResponse
{
public int code { get; set; }
public string status { get; set; }
public string etag { get; set; }
public Data data { get; set; }
}
public class Data
{
public int offset { get; set; }
public int limit { get; set; }
public int total { get; set; }
public int count { get; set; }
public Result[] results { get; set; }
}
public class Result
{
public int id { get; set; }
public string name { get; set; }
public string description { get; set; }
public DateTime modified { get; set; }
public Thumbnail thumbnail { get; set; }
public string resourceURI { get; set; }
public Comics comics { get; set; }
public Series series { get; set; }
public Stories stories { get; set; }
public Events events { get; set; }
public Url[] urls { get; set; }
}
public class Thumbnail
{
public string path { get; set; }
public string extension { get; set; }
}
public class Comics
{
public int available { get; set; }
public string collectionURI { get; set; }
public ComicResourceUriItem[] items { get; set; }
public int returned { get; set; }
}
public class ComicResourceUriItem
{
public string resourceURI { get; set; }
public string name { get; set; }
}
public class Series
{
public int available { get; set; }
public string collectionURI { get; set; }
public SeriesResourceItem[] items { get; set; }
public int returned { get; set; }
}
public class SeriesResourceItem
{
public string resourceURI { get; set; }
public string name { get; set; }
}
public class Stories
{
public int available { get; set; }
public string collectionURI { get; set; }
public StoriesResourceItem[] items { get; set; }
public int returned { get; set; }
}
public class StoriesResourceItem
{
public string resourceURI { get; set; }
public string name { get; set; }
public string type { get; set; }
}
public class Events
{
public int available { get; set; }
public string collectionURI { get; set; }
public EventsResourceUriItem[] items { get; set; }
public int returned { get; set; }
}
public class EventsResourceUriItem
{
public string resourceURI { get; set; }
public string name { get; set; }
}
public class Url
{
public string type { get; set; }
public string url { get; set; }
}
}
This was a huge help! Hope someone else finds it useful.

Categories

Resources