Problems deserializing Json from MusixMatch API? - c#
I'm trying to implement MusixMatch API, I must admit, when I debug I'm unable to see what's in the ObservableCollection after the API call because the debugger jumps to another thread (I have zero expertise in thread management), however I can see what's the from the API response, Visual Studio says is not Json formatted:
HttpClient httpClient = new HttpClient();
var response = await httpClient.GetStringAsync($"https://api.musixmatch.com/ws/1.1/artist.search?format=jsonp&callback=callback&q_artist=queen&page=1&page_size=5&apikey={apikey}");
RootObject testList= JsonConvert.DeserializeObject<RootObject>(response);
return testList;
I have a model with this structure:
public class Header
{
public int status_code { get; set; }
public double execute_time { get; set; }
public int available { get; set; }
}
public class ArtistNameTranslation
{
public string language { get; set; }
public string translation { get; set; }
}
public class ArtistNameTranslationList
{
public ArtistNameTranslation artist_name_translation { get; set; }
}
public class ArtistAliasList
{
public string artist_alias { get; set; }
}
public class ArtistCredits
{
public List<object> artist_list { get; set; }
}
public class Artist
{
public int artist_id { get; set; }
public string artist_name { get; set; }
public List<ArtistNameTranslationList> artist_name_translation_list { get; set; }
public string artist_comment { get; set; }
public string artist_country { get; set; }
public List<ArtistAliasList> artist_alias_list { get; set; }
public int artist_rating { get; set; }
public string artist_twitter_url { get; set; }
public ArtistCredits artist_credits { get; set; }
public int restricted { get; set; }
public DateTime updated_time { get; set; }
}
public class ArtistList
{
public Artist artist { get; set; }
}
public class Body
{
public List<ArtistList> artist_list { get; set; }
}
public class Message
{
public Header header { get; set; }
public Body body { get; set; }
}
public class RootObject
{
public Message message { get; set; }
}
}
As I said I was able to see what's in the response from the API, you can look at the complete response:
callback({"message":{"header": {"status_code":200,"execute_time":0.043232917785645,"available":6936},"body":{"artist_list":[{"artist":{"artist_id":118,"artist_name":"Queen","artist_name_translation_list":[{"artist_name_translation":{"language":"JA","translation":"\u30af\u30a4\u30fc\u30f3"}}],"artist_comment":"","artist_country":"","artist_alias_list":[{"artist_alias":"\u30af\u30a4\u30fc\u30f3"},{"artist_alias":"Queen + Adam Lambert"}],"artist_rating":99,"artist_twitter_url":"","artist_credits":{"artist_list":[]},"restricted":0,"updated_time":"2015-12-16T15:50:53Z"}},{"artist":{"artist_id":13755603,"artist_name":"Queen with David Bowie","artist_name_translation_list":[{"artist_name_translation":{"language":"EN","translation":"Queen"}}],"artist_comment":"","artist_country":"","artist_alias_list":[{"artist_alias":"Queen"}],"artist_rating":38,"artist_twitter_url":"","artist_credits":{"artist_list":[{"artist":{"artist_id":118,"artist_name":"Queen","artist_name_translation_list":[{"artist_name_translation":{"language":"JA","translation":"\u30af\u30a4\u30fc\u30f3"}}],"artist_comment":"","artist_country":"","artist_alias_list":[{"artist_alias":"\u30af\u30a4\u30fc\u30f3"},{"artist_alias":"Queen + Adam Lambert"}],"artist_rating":99,"artist_twitter_url":"","artist_credits":{"artist_list":[]},"restricted":0,"updated_time":"2015-12-16T15:50:53Z"}},{"artist":{"artist_id":431,"artist_name":"David Bowie","artist_name_translation_list":[{"artist_name_translation":{"language":"JA","translation":"\u30c7\u30f4\u30a3\u30c3\u30c9\u30fb\u30dc\u30a6\u30a4"}}],"artist_comment":"","artist_country":"GB","artist_alias_list":[{"artist_alias":"\u30c7\u30f4\u30a3\u30c3\u30c9\u30fb\u30dc\u30a6\u30a4"},{"artist_alias":"David Robert Jones"},{"artist_alias":"David Jones"},{"artist_alias":"Ziggy Stardust"},{"artist_alias":"\ub370\uc774\ube44\ub4dc \ubcf4\uc704"},{"artist_alias":"\u0414\u044d\u0432\u0438\u0434 \u0411\u043e\u0443\u0438"},{"artist_alias":"Davis Bowie"},{"artist_alias":"Bowie"},{"artist_alias":"\u30c7\u30d3\u30c3\u30c9\u30fb\u30dc\u30a6\u30a4"},{"artist_alias":"David Bowie"},{"artist_alias":"Davie Bowie"},{"artist_alias":"The Thin White Duke"}],"artist_rating":85,"artist_twitter_url":"","artist_credits":{"artist_list":[]},"restricted":0,"updated_time":"2018-10-20T16:37:59Z"}}]},"restricted":0,"updated_time":"2015-12-01T18:35:35Z"}},{"artist":{"artist_id":17057,"artist_name":"Queen Latifah","artist_name_translation_list":[{"artist_name_translation":{"language":"JA","translation":"\u30af\u30a4\u30fc\u30f3\u30fb\u30e9\u30c6\u30a3\u30d5\u30a1"}}],"artist_comment":"","artist_country":"US","artist_alias_list":[{"artist_alias":"\u30af\u30a4\u30fc\u30f3\u30fb\u30e9\u30c6\u30a3\u30d5\u30a1"},{"artist_alias":"Queen Latifa"},{"artist_alias":"Dana Owens"}],"artist_rating":46,"artist_twitter_url":"","artist_credits":{"artist_list":[]},"restricted":0,"updated_time":"2013-11-05T11:25:25Z"}},{"artist":{"artist_id":7321,"artist_name":"Queens of the Stone Age","artist_name_translation_list":[{"artist_name_translation":{"language":"RU","translation":"Queens Of The Stone Age"}}],"artist_comment":"","artist_country":"US","artist_alias_list":[{"artist_alias":"\u30af\u30a4\u30fc\u30f3\u30ba\u30aa\u30d6\u30b6\u30b9\u30c8\u30fc\u30f3\u30a8\u30a4\u30b8"},{"artist_alias":"Queens Of The Stone Age"},{"artist_alias":"shiqishidaihuanghou"},{"artist_alias":"Queen Of Stoneage"},{"artist_alias":"Queens Of The Stoneage"},{"artist_alias":"QOTSA"}],"artist_rating":76,"artist_twitter_url":"https:\/\/twitter.com\/qotsa","artist_credits":{"artist_list":[]},"restricted":0,"updated_time":"2015-12-09T18:04:11Z"}},{"artist":{"artist_id":26029011,"artist_name":"\u5973\u738b\u8702","artist_name_translation_list":[{"artist_name_translation":{"language":"EN","translation":"Queen Bee"}}],"artist_comment":"","artist_country":"JP","artist_alias_list":[{"artist_alias":"Queen Bee"}],"artist_rating":48,"artist_twitter_url":"","artist_credits":{"artist_list":[]},"restricted":0,"updated_time":"2019-07-15T13:55:16Z"}}]}}});
(https://drive.google.com/file/d/1RH9qxrCfKOXdX16eKy74iWhtbnfT46mD/view?usp=sharing)
As I said, Visual Studio is telling me that the response is not in Json>
(https://drive.google.com/file/d/1MoZlKEIbh8Epp_CC9gukWYtMBwp5oXwy/view?usp=sharing)
Looks like you are passing a parameter format=jsonp in the URL. JSONP is a format where JSON data is wrapped in a callback function. It is intended to be used from within <script> tags in HTML pages. If you want plain JSON, try changing that parameter to format=json and removing the corresponding callback parameter. Or you could try removing both format and callback parameters, assuming that JSON is the default format.
If that doesn't work, then the other alternative is to strip off the callback() function wrapper from the response string prior to trying to parse it as JSON. You can do that with a helper method like this:
public static string ExtractJson(string text)
{
int i = text.IndexOf('(');
int j = text.LastIndexOf(')');
return i > -1 && j > i ? text.Substring(i + 1, j - i - 1) : null;
}
You need to update your code to:
var response = await httpClient.GetStringAsync($"https://api.musixmatch.com/ws/1.1/artist.search?format=jsonp&callback=callback&q_artist=queen&page=1&page_size=5&apikey={apikey}");
var contents = await response.Content.ReadAsStringAsync();
RootObject testList= JsonConvert.DeserializeObject<RootObject>(contents);
return testList;
Related
PUT Request Does not Convert Snake Case to Pascal Case
I am trying to send a PUT request, but for some reason my API refuses to convert snake case properties The request looks like this: Where mercuryParserResponse looks like this in C#: [JsonObject(NamingStrategyType = typeof(SnakeCaseNamingStrategy))] public class MercuryParserResponseDto { public string Author { get; set; } public string Content { get; set; } public DateTimeOffset DatePublished { get; set; } public string Direction { get; set; } public string Domain { get; set; } public string Excerpt { get; set; } public string LeadImageUrl { get; set; } public string Url { get; set; } [JsonProperty("word_count")] public int WordCount { get; set; } public string NextPageUrl { get; set; } // public int RenderedPages { get; set; } // public string Title { get; set; } [JsonProperty("total_pages")] public int TotalPages { get; set; } } And my API endpoint [HttpPut] public async Task<IActionResult> Put( [FromBody]ImportArticleDto article, CancellationToken cancellationToken = default) { return null; } But article.MercuryParserResponse.WordCount is always 0 (Note that single-word properties such as author are coming through correctly) Why? Why are my Json attributes not working here?
From this answer, using JsonPropertyName works: [JsonPropertyName("word_count")] However I don't really want to have to add this to every single property If anyone can advise how to apply this casing to the entire class I will accept your answer
Convert Rest API JSON Response into C# object
I have a code REST API response which is json, and parsing to JObject and pulling a value from it. But i am getting the error when parsing to JObject. Error: "Unexpected character encountered while parsing value: S. Path '', line 0, position 0." Is there any other way to convert Json string to C# object. I have the following code: using Newtonsoft.Json; using (HttpResponseMessage message = httpclient.GetAsync(folderIdURL).Result) { if(message.IsSuccessStatusCode) { var dataobjects = message.Content.ReadAsStringAsync(); //dataobjects = "{"id":"https://gbc-dev5.cloud.wc.com/DctmRest/repositories/dmgbsap_crt/","title":"DQL query results","author":[{"name":"EMC Documentum"}],"updated":"2019-05-02T15:19:52.508+00:00","page":1,"items-per-page":100,"links":[{"rel":"self","href":"https://gbc-dev5.cloud.wc.com/DctmRest/repositories/dmgbsap_crt/?dql=SELECT%20r_object_id%2cobject_name%20FROM%20dm_sysobject%20WHERE%20FOLDER%20(%27%2fgbc%2fUS%2fOSA-ATTACHMENT%2f2019%27)"}],"entries":[{"id":"https://gbc-dev5.cloud.wc.com/DctmRest/repositories/dmgbsap_crt/?dql=SELECT%20r_object_id%2cobject_name%20FROM%20dm_sysobject%20WHERE%20FOLDER%20(%27%2fgbc%2fUS%2fOSA-ATTACHMENT%2f2019%27)&index=0","title":"0b0111738011c114","updated":"2019-05-02T15:19:52.508+00:00","published":"2019-05-02T15:19:52.508+00:00","links":[{"rel":"edit","href":"https://gbc-dev5.cloud.wc.com/DctmRest/repositories/dmgbsap_crt/objects/0b0111738011c114"}],"content":{"json-root":"query-result","definition":"https://gbc-dev5.cloud.wc.com/DctmRest/repositori es/dmgbsap_crt/types/dm_sysobject","properties":{"r_object_id":"0b0111738011c114","object_name":"04"},"links":[{"rel":"self","href":"https://gbc-dev5.cloud.wc.com/DctmRest/repositories/dmgbsap_crt/objects/0b0111738011c114"}]}},{"id":"https://gbc-dev5.cloud.wc.com/DctmRest/repositories/dmgbsap_crt/?dql=SELECT%20r_object_id%2cobject_name%20FROM%20dm_sysobject%20WHERE%20FOLDER%20(%27%2fgbc%2fUS%2fOSA-ATTACHMENT%2f2019%27)&index=1","title":"0b0111738011c115","updated":"2019-05-02T15:19:52.509+00:00","published":"2019-05-02T15:19:52.509+00:00","links":[{"rel":"edit","href":"https://gbc-dev5.cloud.wc.com/DctmRest/repositories/dmgbsap_crt/objects/0b0111738011c115"}],"content":{"json-root":"query-result","definition":"https://gbc-dev5.cloud.wc.com/DctmRest/repositories/dmgbsap_crt/types/dm_sysobject","properties":{"r_object_id":"0b0111738011c115","object_name":"05"},"links":[{"rel":"self","href":"https://gbc-dev5.cloud.wc.com/DctmRest/repositories/dmgbsap_crt/objects/0b0111738011c115"}]}}]}" JObject responseObj = JObject.Parse(dataobjects.ToString()); String id = (String)responseObj["entries" -->"content"-->"properties"-->"object_name"]; } } } I am expecting the value from (String)responseObject["enteries"]["content"][" properties"]["object_name"]
JObjects are a pain. You could get a sample of the JSON response and paste it into a converter like json2csharp.com. It will generate a class for you which you can then use like so: Generated Class: public class MyClass { public string SomeProperty { get; set; } public string AnotherProperty { get; set; } } Usage: if (message.IsSuccessStatusCode) { var deserializedObject = JsonConvert.DeserializeObject<MyClass>(response.Content.ReadAsStringAsync().Result); Console.WriteLine(deserializedObject.SomeProperty); }
I would suggest to follow those steps: You need to check that your json is actually a json, because an error says it is not. You can use online tools like this If possible, avoid JObject and generate real classes. It is not that hard if you know the structure, and you can use another online tools Modify your code to use classes so you will have something like: using System; using Newtonsoft.Json; namespace ConsoleApp11 { class Program { public class Message { public Enteries enteries { get; set; } } public class Enteries { public Content content { get; set; } } public class Content { public Properties properties { get; set; } } public class Properties { public string object_name { get; set; } } static void Main(string[] args) { var input = "{\"enteries\":{\"content\":{ \"properties\":{ \"object_name\":\"your value string\"}}}}"; Message msg = JsonConvert.DeserializeObject<Message>(input); Console.WriteLine(msg?.enteries?.content?.properties?.object_name ?? "no value"); Console.ReadKey(); } } } I hope it helps 😊
Thank you so much for all the help and trips. Finally i am able to get the required value from JSON string. Here is the Final code json2csharp.com public class Author { public string name { get; set; } } public class Link { public string rel { get; set; } public string href { get; set; } } public class Link2 { public string rel { get; set; } public string href { get; set; } } public class Properties { public string r_object_id { get; set; } public string object_name { get; set; } } public class Link3 { public string rel { get; set; } public string href { get; set; } } public class Content { public string json_root { get; set; } public string definition { get; set; } public Properties properties { get; set; } public List<Link3> links { get; set; } } public class Entry { public string id { get; set; } public string title { get; set; } public DateTime updated { get; set; } public DateTime published { get; set; } public List<Link2> links { get; set; } public Content content { get; set; } } public class RootObject { public string id { get; set; } public string title { get; set; } public List<Author> author { get; set; } public DateTime updated { get; set; } public int page { get; set; } public int items_per_page { get; set; } public List<Link> links { get; set; } public List<Entry> entries { get; set; } }
Using Newtonsoft.Json First get the list of entries from the responseObj. Then loop each entries and use LINQ to JSON to get values by property name or index. You can use Item[Object] index on JObject/JArray and then cast the returned JValue to the type you want JObject responseObj = JObject.Parse(dataobjects.ToString()); // get JSON result objects into a list IList<JToken> entries = responseObj ["entries"].Children().ToList(); foreach(JToken entry in entries) { string object_name = (string) entry["content"]["properties"]["object_name"]; }
Unable to deserialize JSON in c#
I am getting the below JSON in response from a REST API. { "data":{ "id":123, "zoneid":"mydomain.com", "parent_id":null, "name":"jaz", "content":"172.1 6.15.235", "ttl":60, "priority":null, "type":"A", "regions":[ "global" ], "system_record":false, "created_at":"2017-09-28T12:12:17Z", "updated_at":"2017-09-28T12:12:17Z" } } and trying to resolve using below code but that doesn't result in a correctly deserialized type. var model = JsonConvert.DeserializeObject<ResponseModel>(response); below is a class according the field I received in JSON response. public class ResponseModel { public int id { get; set; } public string zone_id { get; set; } public int parent_id { get; set; } public string name { get; set; } public string content { get; set; } public int ttl { get; set; } public int priority { get; set; } public string type { get; set; } public string[] regions { get; set; } public bool system_record { get; set; } public DateTime created_at { get; set; } public DateTime updated_at { get; set; } } What is missing?
You're missing a wrapper class. public class Wrapper { public ResponseModel data {get;set} } and then do: var model = JsonConvert.DeserializeObject<Wrapper>(response).data; to get the instance of your ResponseModel out the data property. You can deduct this from your json: { "data": { "id":123, /*rest omitted */ } } The type that will receive this JSON needs to have a property named data. The suggested Wrapper class acts as that type.
According to json2csharp website, your model seems to be incorrect. Try this one : public class ResponseModel { public int id { get; set; } public string zoneid { get; set; } public object parent_id { get; set; } public string name { get; set; } public string content { get; set; } public int ttl { get; set; } public object priority { get; set; } public string type { get; set; } public List<string> regions { get; set; } public bool system_record { get; set; } public DateTime created_at { get; set; } public DateTime updated_at { get; set; } } public class RootObject { public ResponseModel data { get; set; } }
Here a cool trick you can do in Visual Studio 2015-2017 where it generates the the correct class if you just copy the JSON (ctrl + c). You need to create a new class in visual studio and once inside the class go to Edit menu -> Paste special -> paste JSON As Classes. Steps to generate json class This will generate the C# object for that json for you and save you all the hassle :)
Your model does not match your response - it matches the data property. Simply wrap another object round it public class ResponseData { public ResponseModel Data {get; set; { } and then var model = JsonConvert.DeserializeObject<ResponseData>(response);
Deserialize Google Directions JSON
First time working with JSON and related, I'm trying to get distance/duration of all possible routes from this request: https://maps.googleapis.com/maps/api/directions/json?origin=41.2091585,-8.5763016&destination=41.258913,-8.636942&mode=driving&alternatives=true&avoid=tolls&language=pt-PT&key=AIzaSyDuhdvLAny3MpraXKX-bahkXZJolm7KLbE I got the following classes using "Paste JSON as Classes" and create one Class for each of the following ones: public class Rootobject { public Geocoded_Waypoints[] geocoded_waypoints { get; set; } public Route[] routes { get; set; } public string status { get; set; } } public class Route { public Bounds bounds { get; set; } public string copyrights { get; set; } public Leg[] legs { get; set; } public Overview_Polyline overview_polyline { get; set; } public string summary { get; set; } public object[] warnings { get; set; } public object[] waypoint_order { get; set; } } public class Leg { public Distance distance { get; set; } public Duration duration { get; set; } public string end_address { get; set; } public End_Location end_location { get; set; } public string start_address { get; set; } public Start_Location start_location { get; set; } public Step[] steps { get; set; } public object[] traffic_speed_entry { get; set; } public Via_Waypoint[] via_waypoint { get; set; } } public class Distance { public string text { get; set; } public int value { get; set; } } public class Duration { public string text { get; set; } public int value { get; set; } } For the query mentioned above I have 3 different routes (aka "legs") and I want to get the distance/duration of each one. I came up with the following but it's not working. HttpWebRequest request = (HttpWebRequest)WebRequest.Create(query); HttpWebResponse response = (HttpWebResponse)request.GetResponse(); using (var streamReader = new StreamReader(response.GetResponseStream())) { var result = streamReader.ReadToEnd(); if (!string.IsNullOrEmpty(result)) { Distance t = JsonConvert.DeserializeObject<Distance>(result); string distance1_Value = t.value; string distance1_Text = t.text; Duration d = JsonConvert.DeserializeObject<Duration>(result); string duration1_Value = d.value; string duration1_Value = d.text; } } Any help? PS: If anyone can show me how to iterate throw each "legs" that would be great. EDIT: Forgot to mention I'm using Newtonsoft.
I found the solution a few days ago... First, i do the same of you, but still not working for me, so i take a look deep inside the classes auto generated by this tool and notice that some classes was missing the 's' at the end of its names.. Step, where correct name 'Steps' Leg. correct name 'Legs' Route. correct name 'Routes' Do you have to fix this at entire document. After this, you can convert directly... Take a look at correct answer: [1]: http://pastie.org/10935748#9
Navigating JSON data in c#
I'm trying to check if a twitch.tv stream is online or not via c#. Currently I have: private bool checkStream(String chan) { using (var w = new WebClient()) { String json_data = w.DownloadString("https://api.twitch.tv/kraken/streams/" + chan); JObject stream = JObject.Parse(json_data); print(json_data); //just for testing purposes if (stream["stream"] != null) { print("YIPPEE"); } } return false; } Here's the twitch JSON API for what I'm downloading: https://github.com/justintv/Twitch-API/blob/master/v2_resources/streams.md#get-streamschannel As you can see, if a stream is currently offline, the stream field just says null. But obviously, it's still there, so my if(stream["stream"]!=null) check doesn't work. Never used JSON or Newtonsoft's json.net before, so I'm kind of at a loss for what to do. Thanks in advance for any help!
You need to create a class that you can de-serialize the json to. For instance, if you receive json that looks like this MyJson = { Prop1 : "Property1", Prop2 : "Property2" } then you'll need to create a class that acts as a contract between your program and the JSON stream. public class MyJsonClass{ public string Prop1; public string Prop2; public MyJsonClass(){ } } Now, you can deserialize the json to your C# class and check it for any null values: // Create a MyJson class instance by deserializing your json string string myJsonString = ...//get your json string MyJsonClass deserialized = JsonConvert.DeserializeObject<MyJsonClass>(myJsonString); if ( deserialized.Prop1 == null ) //etc etc etc
Here's a full processor for that Json response (Disclaimer: I used http://json2csharp.com/ for this code ) : public class Links { public string channel { get; set; } public string self { get; set; } } public class Links2 { public string self { get; set; } } public class Links3 { public string stream_key { get; set; } public string editors { get; set; } public string subscriptions { get; set; } public string commercial { get; set; } public string videos { get; set; } public string follows { get; set; } public string self { get; set; } public string chat { get; set; } public string features { get; set; } } public class Channel { public string display_name { get; set; } public Links3 _links { get; set; } public List<object> teams { get; set; } public string status { get; set; } public string created_at { get; set; } public string logo { get; set; } public string updated_at { get; set; } public object mature { get; set; } public object video_banner { get; set; } public int _id { get; set; } public string background { get; set; } public string banner { get; set; } public string name { get; set; } public string url { get; set; } public string game { get; set; } } public class Stream { public Links2 _links { get; set; } public string broadcaster { get; set; } public string preview { get; set; } public long _id { get; set; } public int viewers { get; set; } public Channel channel { get; set; } public string name { get; set; } public string game { get; set; } } public class RootObject { public Links _links { get; set; } public Stream stream { get; set; } } and here's how to use it : bool StreamOnline = false; using (var w = new WebClient()) { var jsonData = w.DownloadData("https://api.twitch.tv/kraken/streams/" + + chan); var s = new DataContractJsonSerializer(typeof(RootObject)); using (var ms = new MemoryStream(jsonData)) { var obj = (RootObject)s.ReadObject(ms); StreamOnline = obj.stream == null; } } return StreamOnline; Please note that you need to reference System.Runtime.Serialization and add using System.Runtime.Serialization.Json; to use DataContractJsonSerializer. If you don't need every detail just make the stream property of type object (in the RootObject class) and check whether it's null or not.
Have you tried this. The HasValues is a bool property that checks if there are child tokens, if its value is null there will not be any child tokens. if (stream["stream"].HasValues) { print("YIPPEE"); }else { print("No Stream"); }