Getting data from Steam Store API using Newtonsoft.Json - c#

I am trying to get the data from the Steam Store API. The goal is to pass it an AppID and then get the data for that game using the API and storing it in a Game object. I am fetching the data up until serialization. The below is the code I an using:
namespace GData
{
public class Rootobject
{
public Game _9050 { get; set; }
}
public class Game
{
public bool success { get; set; }
public Data data { get; set; }
}
public class Data
{
public string type { get; set; }
public string name { get; set; }
public int steam_appid { get; set; }
public int required_age { get; set; }
public bool is_free { get; set; }
public string detailed_description { get; set; }
public string about_the_game { get; set; }
public string short_description { get; set; }
public string supported_languages { get; set; }
public string header_image { get; set; }
public string website { get; set; }
public Pc_Requirements pc_requirements { get; set; }
public object[] mac_requirements { get; set; }
public object[] linux_requirements { get; set; }
public string[] developers { get; set; }
public string[] publishers { get; set; }
public Price_Overview price_overview { get; set; }
public int[] packages { get; set; }
public Package_Groups[] package_groups { get; set; }
public Platforms platforms { get; set; }
public Metacritic metacritic { get; set; }
public Category[] categories { get; set; }
public Genre[] genres { get; set; }
public Screenshot[] screenshots { get; set; }
public Recommendations recommendations { get; set; }
public Release_Date release_date { get; set; }
public Support_Info support_info { get; set; }
public string background { get; set; }
}
public class Pc_Requirements
{
public string minimum { get; set; }
}
public class Price_Overview
{
public string currency { get; set; }
public int initial { get; set; }
public int final { get; set; }
public int discount_percent { get; set; }
}
public class Platforms
{
public bool windows { get; set; }
public bool mac { get; set; }
public bool linux { get; set; }
}
public class Metacritic
{
public int score { get; set; }
public string url { get; set; }
}
public class Recommendations
{
public int total { get; set; }
}
public class Release_Date
{
public bool coming_soon { get; set; }
public string date { get; set; }
}
public class Support_Info
{
public string url { get; set; }
public string email { get; set; }
}
public class Package_Groups
{
public string name { get; set; }
public string title { get; set; }
public string description { get; set; }
public string selection_text { get; set; }
public string save_text { get; set; }
public int display_type { get; set; }
public string is_recurring_subscription { get; set; }
public Sub[] subs { get; set; }
}
public class Sub
{
public int packageid { get; set; }
public string percent_savings_text { get; set; }
public int percent_savings { get; set; }
public string option_text { get; set; }
public string option_description { get; set; }
public string can_get_free_license { get; set; }
public bool is_free_license { get; set; }
public int price_in_cents_with_discount { get; set; }
}
public class Category
{
public int id { get; set; }
public string description { get; set; }
}
public class Genre
{
public string id { get; set; }
public string description { get; set; }
}
public class Screenshot
{
public int id { get; set; }
public string path_thumbnail { get; set; }
public string path_full { get; set; }
}
}
Fetching JSON:
public class GameData
{
public Game GetGameData(int GameId)
{
var url = "https://store.steampowered.com/api/appdetails/?appids=" + GameId.ToString();
//Game GameData = _download_serialized_json_data<Game>(url);
HttpWebRequest WebReq = (HttpWebRequest)WebRequest.Create(string.Format(url));
WebReq.Method = "GET";
HttpWebResponse WebResp = (HttpWebResponse)WebReq.GetResponse();
Console.WriteLine(WebResp.StatusCode);
Console.WriteLine(WebResp.Server);
string jsonString;
using (Stream stream = WebResp.GetResponseStream())
{
StreamReader reader = new StreamReader(stream, System.Text.Encoding.UTF8);
jsonString = reader.ReadToEnd();
}
Game GameData = new Game();
GameData = JsonConvert.DeserializeObject<Game>(jsonString);
return GameData;
}
}
The code is returning success: false.
The issue seems to be in the deserialization as the jsonString = reader.ReadToEnd(); jsonString variable is getting full with the data.
Is there something wrong in the Game class?
I am using C# and the Newtonsoft JSON library.
Sample JSON retrieved in jsonString (https://store.steampowered.com/api/appdetails/?appids=570):
{
"570":{
"success":true,
"data":{
"type":"game",
"name":"Dota 2",
"steam_appid":570,
"required_age":0,
"is_free":true,
"dlc":[
859040
],
"detailed_description":"<strong>The most-played game on Steam.<\/strong><br>Every day, millions of players worldwide enter battle as one of over a hundred Dota heroes. And no matter if it's their 10th hour of play or 1,000th, there's always something new to discover. With regular updates that ensure a constant evolution of gameplay, features, and heroes, Dota 2 has truly taken on a life of its own.<br><br><strong>One Battlefield. Infinite Possibilities.<\/strong><br>When it comes to diversity of heroes, abilities, and powerful items, Dota boasts an endless array\u2014no two games are the same. Any hero can fill multiple roles, and there's an abundance of items to help meet the needs of each game. Dota doesn't provide limitations on how to play, it empowers you to express your own style.<br><br><strong>All heroes are free.<\/strong><br>Competitive balance is Dota's crown jewel, and to ensure everyone is playing on an even field, the core content of the game\u2014like the vast pool of heroes\u2014is available to all players. Fans can collect cosmetics for heroes and fun add-ons for the world they inhabit, but everything you need to play is already included before you join your first match.<br><br><strong>Bring your friends and party up.<\/strong><br>Dota is deep, and constantly evolving, but it's never too late to join. <br>Learn the ropes playing co-op vs. bots. Sharpen your skills in the hero demo mode. Jump into the behavior- and skill-based matchmaking system that ensures you'll <br>be matched with the right players each game.",
"about_the_game":"<strong>The most-played game on Steam.<\/strong><br>Every day, millions of players worldwide enter battle as one of over a hundred Dota heroes. And no matter if it's their 10th hour of play or 1,000th, there's always something new to discover. With regular updates that ensure a constant evolution of gameplay, features, and heroes, Dota 2 has truly taken on a life of its own.<br><br><strong>One Battlefield. Infinite Possibilities.<\/strong><br>When it comes to diversity of heroes, abilities, and powerful items, Dota boasts an endless array\u2014no two games are the same. Any hero can fill multiple roles, and there's an abundance of items to help meet the needs of each game. Dota doesn't provide limitations on how to play, it empowers you to express your own style.<br><br><strong>All heroes are free.<\/strong><br>Competitive balance is Dota's crown jewel, and to ensure everyone is playing on an even field, the core content of the game\u2014like the vast pool of heroes\u2014is available to all players. Fans can collect cosmetics for heroes and fun add-ons for the world they inhabit, but everything you need to play is already included before you join your first match.<br><br><strong>Bring your friends and party up.<\/strong><br>Dota is deep, and constantly evolving, but it's never too late to join. <br>Learn the ropes playing co-op vs. bots. Sharpen your skills in the hero demo mode. Jump into the behavior- and skill-based matchmaking system that ensures you'll <br>be matched with the right players each game.",
"short_description":"Every day, millions of players worldwide enter battle as one of over a hundred Dota heroes. And no matter if it's their 10th hour of play or 1,000th, there's always something new to discover. With regular updates that ensure a constant evolution of gameplay, features, and heroes, Dota 2 has truly taken on a life of its own.",
"supported_languages":"Bulgarian, Czech, Danish, Dutch, English<strong>*<\/strong>, Finnish, French, German, Greek, Hungarian, Italian, Japanese, Korean<strong>*<\/strong>, Norwegian, Polish, Portuguese, Portuguese-Brazil, Romanian, Russian, Simplified Chinese<strong>*<\/strong>, Spanish, Swedish, Thai, Traditional Chinese, Turkish, Ukrainian<br><strong>*<\/strong>languages with full audio support",
"reviews":"\u201cA modern multiplayer masterpiece.\u201d<br>9.5\/10 \u2013 <a href=\"https:\/\/www.destructoid.com\/review-dota-2-258506.phtml\" target=\"_blank\" rel=\"noreferrer\" >Destructoid<\/a><br><br>\u201cOnce you start to learn its secrets, there\u2019s a wild and exciting variety of play here that\u2019s unmatched, even by its peers.\u201d<br>9.4\/10 \u2013 <a href=\"http:\/\/www.ign.com\/articles\/2013\/07\/24\/dota-2-review\" target=\"_blank\" rel=\"noreferrer\" >IGN<\/a><br><br>\u201cDota 2 is possibly the only competitive free-to-play game that is totally uncompromised by its business model.\u201d<br>90\/100 \u2013 <a href=\"http:\/\/www.pcgamer.com\/dota-2-review-2\/\" target=\"_blank\" rel=\"noreferrer\" >PC Gamer<\/a><br>",
"header_image":"https:\/\/steamcdn-a.akamaihd.net\/steam\/apps\/570\/header.jpg?t=1525818062",
"website":"http:\/\/www.dota2.com\/",
"pc_requirements":{
"minimum":"<strong>Minimum:<\/strong><br><ul class=\"bb_ul\"><li><strong>OS:<\/strong> Windows 7 or newer<br><\/li><li><strong>Processor:<\/strong> Dual core from Intel or AMD at 2.8 GHz<br><\/li><li><strong>Memory:<\/strong> 4 GB RAM<br><\/li><li><strong>Graphics:<\/strong> nVidia GeForce 8600\/9600GT, ATI\/AMD Radeon HD2600\/3600<br><\/li><li><strong>DirectX:<\/strong> Version 9.0c<br><\/li><li><strong>Network:<\/strong> Broadband Internet connection<br><\/li><li><strong>Storage:<\/strong> 15 GB available space<br><\/li><li><strong>Sound Card:<\/strong> DirectX Compatible<\/li><\/ul>"
},
"mac_requirements":{
"minimum":"<strong>Minimum:<\/strong><br><ul class=\"bb_ul\"><li><strong>OS:<\/strong> OS X Mavericks 10.9 or newer<br><\/li><li><strong>Processor:<\/strong> Dual core from Intel<br><\/li><li><strong>Memory:<\/strong> 4 GB RAM<br><\/li><li><strong>Graphics:<\/strong> nVidia 320M or higher, or Radeon HD 2400 or higher, or Intel HD 3000 or higher<br><\/li><li><strong>Network:<\/strong> Broadband Internet connection<br><\/li><li><strong>Storage:<\/strong> 15 GB available space<\/li><\/ul>"
},
"linux_requirements":{
"minimum":"<strong>Minimum:<\/strong><br><ul class=\"bb_ul\"><li><strong>OS:<\/strong> Ubuntu 12.04 or newer<br><\/li><li><strong>Processor:<\/strong> Dual core from Intel or AMD at 2.8 GHz<br><\/li><li><strong>Memory:<\/strong> 4 GB RAM<br><\/li><li><strong>Graphics:<\/strong> nVidia Geforce 8600\/9600GT (Driver v331), AMD HD 2xxx-4xxx (Driver mesa 10.5.9), AMD HD 5xxx+ (Driver mesa 10.5.9 or Catalyst 15.7), Intel HD 3000 (Driver mesa 10.6)<br><\/li><li><strong>Network:<\/strong> Broadband Internet connection<br><\/li><li><strong>Storage:<\/strong> 15 GB available space<br><\/li><li><strong>Sound Card:<\/strong> OpenAL Compatible Sound Card<\/li><\/ul>"
},
"developers":[
"Valve"
],
"publishers":[
"Valve"
],
"packages":[
197846
],
"package_groups":[
{
"name":"default",
"title":"Buy Dota 2",
"description":"",
"selection_text":"Select a purchase option",
"save_text":"",
"display_type":0,
"is_recurring_subscription":"false",
"subs":[
{
"packageid":197846,
"percent_savings_text":"",
"percent_savings":0,
"option_text":"Dota 2 - Commercial License - Free",
"option_description":"",
"can_get_free_license":"0",
"is_free_license":true,
"price_in_cents_with_discount":0
}
]
}
],
"platforms":{
"windows":true,
"mac":true,
"linux":true
},
"metacritic":{
"score":90,
"url":"http:\/\/www.metacritic.com\/game\/pc\/dota-2?ftag=MCD-06-10aaa1f"
},
"categories":[
{
"id":1,
"description":"Multi-player"
},
{
"id":9,
"description":"Co-op"
},
{
"id":29,
"description":"Steam Trading Cards"
},
{
"id":30,
"description":"Steam Workshop"
},
{
"id":40,
"description":"SteamVR Collectibles"
},
{
"id":35,
"description":"In-App Purchases"
},
{
"id":8,
"description":"Valve Anti-Cheat enabled"
}
],
"genres":[
{
"id":"1",
"description":"Action"
},
{
"id":"37",
"description":"Free to Play"
},
{
"id":"2",
"description":"Strategy"
}
],
"screenshots":[
{
"id":0,
"path_thumbnail":"https:\/\/steamcdn-a.akamaihd.net\/steam\/apps\/570\/ss_86d675fdc73ba10462abb8f5ece7791c5047072c.600x338.jpg?t=1525818062",
"path_full":"https:\/\/steamcdn-a.akamaihd.net\/steam\/apps\/570\/ss_86d675fdc73ba10462abb8f5ece7791c5047072c.1920x1080.jpg?t=1525818062"
},
{
"id":1,
"path_thumbnail":"https:\/\/steamcdn-a.akamaihd.net\/steam\/apps\/570\/ss_ad8eee787704745ccdecdfde3a5cd2733704898d.600x338.jpg?t=1525818062",
"path_full":"https:\/\/steamcdn-a.akamaihd.net\/steam\/apps\/570\/ss_ad8eee787704745ccdecdfde3a5cd2733704898d.1920x1080.jpg?t=1525818062"
},
{
"id":2,
"path_thumbnail":"https:\/\/steamcdn-a.akamaihd.net\/steam\/apps\/570\/ss_7ab506679d42bfc0c0e40639887176494e0466d9.600x338.jpg?t=1525818062",
"path_full":"https:\/\/steamcdn-a.akamaihd.net\/steam\/apps\/570\/ss_7ab506679d42bfc0c0e40639887176494e0466d9.1920x1080.jpg?t=1525818062"
},
{
"id":3,
"path_thumbnail":"https:\/\/steamcdn-a.akamaihd.net\/steam\/apps\/570\/ss_c9118375a2400278590f29a3537769c986ef6e39.600x338.jpg?t=1525818062",
"path_full":"https:\/\/steamcdn-a.akamaihd.net\/steam\/apps\/570\/ss_c9118375a2400278590f29a3537769c986ef6e39.1920x1080.jpg?t=1525818062"
},
{
"id":4,
"path_thumbnail":"https:\/\/steamcdn-a.akamaihd.net\/steam\/apps\/570\/ss_f9ebafedaf2d5cfb80ef1f74baa18eb08cad6494.600x338.jpg?t=1525818062",
"path_full":"https:\/\/steamcdn-a.akamaihd.net\/steam\/apps\/570\/ss_f9ebafedaf2d5cfb80ef1f74baa18eb08cad6494.1920x1080.jpg?t=1525818062"
},
{
"id":5,
"path_thumbnail":"https:\/\/steamcdn-a.akamaihd.net\/steam\/apps\/570\/ss_27b6345f22243bd6b885cc64c5cda74e4bd9c3e8.600x338.jpg?t=1525818062",
"path_full":"https:\/\/steamcdn-a.akamaihd.net\/steam\/apps\/570\/ss_27b6345f22243bd6b885cc64c5cda74e4bd9c3e8.1920x1080.jpg?t=1525818062"
},
{
"id":6,
"path_thumbnail":"https:\/\/steamcdn-a.akamaihd.net\/steam\/apps\/570\/ss_b33a65678dc71cc98df4890e22a89601ee56a918.600x338.jpg?t=1525818062",
"path_full":"https:\/\/steamcdn-a.akamaihd.net\/steam\/apps\/570\/ss_b33a65678dc71cc98df4890e22a89601ee56a918.1920x1080.jpg?t=1525818062"
},
{
"id":7,
"path_thumbnail":"https:\/\/steamcdn-a.akamaihd.net\/steam\/apps\/570\/ss_d0f973ce376ca5b6c08e081cb035e86ced105fa9.600x338.jpg?t=1525818062",
"path_full":"https:\/\/steamcdn-a.akamaihd.net\/steam\/apps\/570\/ss_d0f973ce376ca5b6c08e081cb035e86ced105fa9.1920x1080.jpg?t=1525818062"
},
{
"id":8,
"path_thumbnail":"https:\/\/steamcdn-a.akamaihd.net\/steam\/apps\/570\/ss_1f3b5f5ccf8b159294914c3fe028128a787304b6.600x338.jpg?t=1525818062",
"path_full":"https:\/\/steamcdn-a.akamaihd.net\/steam\/apps\/570\/ss_1f3b5f5ccf8b159294914c3fe028128a787304b6.1920x1080.jpg?t=1525818062"
},
{
"id":9,
"path_thumbnail":"https:\/\/steamcdn-a.akamaihd.net\/steam\/apps\/570\/ss_e0a92f15a6631a8186df79182d0fe28b5e37d8cb.600x338.jpg?t=1525818062",
"path_full":"https:\/\/steamcdn-a.akamaihd.net\/steam\/apps\/570\/ss_e0a92f15a6631a8186df79182d0fe28b5e37d8cb.1920x1080.jpg?t=1525818062"
}
],
"movies":[
{
"id":256692021,
"name":"Dota 2 - Join the Battle",
"thumbnail":"https:\/\/steamcdn-a.akamaihd.net\/steam\/apps\/256692021\/movie.293x165.jpg?t=1501892790",
"webm":{
"480":"http:\/\/steamcdn-a.akamaihd.net\/steam\/apps\/256692021\/movie480.webm?t=1501892790",
"max":"http:\/\/steamcdn-a.akamaihd.net\/steam\/apps\/256692021\/movie_max.webm?t=1501892790"
},
"highlight":true
},
{
"id":256692017,
"name":"Dota 2 - Sizzle Reel",
"thumbnail":"https:\/\/steamcdn-a.akamaihd.net\/steam\/apps\/256692017\/movie.293x165.jpg?t=1501892798",
"webm":{
"480":"http:\/\/steamcdn-a.akamaihd.net\/steam\/apps\/256692017\/movie480.webm?t=1501892798",
"max":"http:\/\/steamcdn-a.akamaihd.net\/steam\/apps\/256692017\/movie_max.webm?t=1501892798"
},
"highlight":true
},
{
"id":2028243,
"name":"Dota 2 - The Greeviling",
"thumbnail":"https:\/\/steamcdn-a.akamaihd.net\/steam\/apps\/2028243\/movie.293x165.jpg?t=1447357208",
"webm":{
"480":"http:\/\/steamcdn-a.akamaihd.net\/steam\/apps\/2028243\/movie480.webm?t=1447357208",
"max":"http:\/\/steamcdn-a.akamaihd.net\/steam\/apps\/2028243\/movie_max.webm?t=1447357208"
},
"highlight":false
},
{
"id":81026,
"name":"Dota 2 Gamescom Trailer",
"thumbnail":"https:\/\/steamcdn-a.akamaihd.net\/steam\/apps\/81026\/movie.293x165.jpg?t=1501892804",
"webm":{
"480":"http:\/\/steamcdn-a.akamaihd.net\/steam\/apps\/81026\/movie480.webm?t=1501892804",
"max":"http:\/\/steamcdn-a.akamaihd.net\/steam\/apps\/81026\/movie_max.webm?t=1501892804"
},
"highlight":false
},
{
"id":2040250,
"name":"Dota 2 Reborn - Custom Games Are Here",
"thumbnail":"https:\/\/steamcdn-a.akamaihd.net\/steam\/apps\/2040250\/movie.293x165.jpg?t=1447376742",
"webm":{
"480":"http:\/\/steamcdn-a.akamaihd.net\/steam\/apps\/2040250\/movie480.webm?t=1447376742",
"max":"http:\/\/steamcdn-a.akamaihd.net\/steam\/apps\/2040250\/movie_max.webm?t=1447376742"
},
"highlight":false
}
],
"recommendations":{
"total":911325
},
"release_date":{
"coming_soon":false,
"date":"9 Jul, 2013"
},
"support_info":{
"url":"http:\/\/dev.dota2.com\/",
"email":""
},
"background":"https:\/\/steamcdn-a.akamaihd.net\/steam\/apps\/570\/page_bg_generated_v6b.jpg?t=1525818062"
}
}
}
UPDATE: if I return Data datatype all value are null
public Data GetGameData(int GameId)
{
var url = "https://store.steampowered.com/api/appdetails/?appids=" + GameId.ToString();
//Game GameData = _download_serialized_json_data<Game>(url);
HttpWebRequest WebReq = (HttpWebRequest)WebRequest.Create(string.Format(url));
WebReq.Method = "GET";
HttpWebResponse WebResp = (HttpWebResponse)WebReq.GetResponse();
Console.WriteLine(WebResp.StatusCode);
Console.WriteLine(WebResp.Server);
string jsonString;
using (Stream stream = WebResp.GetResponseStream())
{
StreamReader reader = new StreamReader(stream, System.Text.Encoding.UTF8);
jsonString = reader.ReadToEnd();
}
var dict = JsonConvert.DeserializeObject<Dictionary<string, Data>>(jsonString);
Data gameData = dict[GameId.ToString()];
return gameData;
}
If I return Game datatype I get the same error:
public Game GetGameData(int GameId)
{
var url = "https://store.steampowered.com/api/appdetails/?appids=" + GameId.ToString();
//Game GameData = _download_serialized_json_data<Game>(url);
HttpWebRequest WebReq = (HttpWebRequest)WebRequest.Create(string.Format(url));
WebReq.Method = "GET";
HttpWebResponse WebResp = (HttpWebResponse)WebReq.GetResponse();
Console.WriteLine(WebResp.StatusCode);
Console.WriteLine(WebResp.Server);
string jsonString;
using (Stream stream = WebResp.GetResponseStream())
{
StreamReader reader = new StreamReader(stream, System.Text.Encoding.UTF8);
jsonString = reader.ReadToEnd();
}
var dict = JsonConvert.DeserializeObject<Dictionary<string, Game>>(jsonString);
Game gameData = dict[GameId.ToString()];
return gameData;
}

In your code, you are attempting to deserialize into a Game class containing success and data properties. However, in sample JSON, these properties are not at the root level. Instead, they are one level further down, inside a property called 570, which I am guessing is the game ID:
{
"570": {
"success": true,
"data": {
...
}
}
}
Since the class you are deserializing into doesn't match up with the JSON, you are getting default values (i.e. success is false and data is null).
To fix this, you will need something to wrap your Game class. And since the game ID will probably change depending on the request, you can't use a regular class like Rootobject. Instead you will need to deserialize into a Dictionary<string, Game> like this:
var dict = JsonConvert.DeserializeObject<Dictionary<string, Game>>(jsonString);
You can then retrieve the Game object from that:
Game gameData = dict[GameId.ToString()];
Here is a working demo: https://dotnetfiddle.net/ieT839
Note: In your classes, you can omit members that you don't really need. In playing around with different game ID's I discovered that the pc_requirements, mac_requirements and linux_requirements elements in the JSON can sometimes be an object and sometimes an array of objects. If you have your classes declared to expect one thing and the JSON returns the other, then you will get an error when deserializing. You can solve this problem using a custom JsonConverter like the SingleOrArrayConverter<T> from How to handle both a single item and an array for the same property using JSON.net. But if you don't really need those items, you can sidestep the issue just by commenting them out in your Data class.

Related

Get multiples Arrays from dictionary Object

I have a JSON call, this brings me an object with four Arrays.
HttpWebRequest apiRequest = WebRequest.Create(url) as HttpWebRequest;
string apiResponse = "";
using (HttpWebResponse response = apiRequest.GetResponse() as HttpWebResponse)
{
StreamReader reader = new StreamReader(response.GetResponseStream());
apiResponse = reader.ReadToEnd();
}
var dict = new JavaScriptSerializer().Deserialize<Dictionary<string, object>>(apiResponse);
var results = dict["results"];
Then i use var dict to storage this four arrays, later i have var results to select an specific array. In this case, the array i want is "results".
var results "output":
The problem is i want access the data for each array, but i don't know how do this.
ArrayList list = (ArrayList)results;
StringBuilder builder = new StringBuilder();
for (int i = 0; i < list.Count; i++)
{
if (builder.Length > 0)
{
builder.Append(", ");
}
object current = list[i];
builder.Append(current);
}
LblTitle.Text = builder.ToString();
I see this code in other post and i adapt to my code, but this only brings me this System.Collections.Generic.Dictionary'2[System.String,System.Object], for each array.
I want something like this
string[] arrayresult = builder.ToString();
string[] arrayresult2 = builder.ToString();
etc, for each array in the object results. And later access each array data like this LblTitle.Text = arrayresult[1]; LblTitle2.Text = arrayresult2[1];
Edit: Adding JSON Example
"{\"page\":1,\"results\":[{\"adult\":false,\"backdrop_path\":\"/7ABsaBkO1jA2psC8Hy4IDhkID4h.jpg\",\"genre_ids\":[28,12,14,878],\"id\":19995,\"original_language\":\"en\",\"original_title\":\"Avatar\",\"overview\":\"In the 22nd century, a paraplegic Marine is dispatched to the moon Pandora on a unique mission, but becomes torn between following orders and protecting an alien civilization.\",\"popularity\":1363.938,\"poster_path\":\"/jRXYjXNq0Cs2TcJjLkki24MLp7u.jpg\",\"release_date\":\"2009-12-10\",\"title\":\"Avatar\",\"video\":false,\"vote_average\":7.5,\"vote_count\":26216},{\"adult\":false,\"backdrop_path\":\"/198vrF8k7mfQ4FjDJsBmdQcaiyq.jpg\",\"genre_ids\":[878,28,12],\"id\":76600,\"original_language\":\"en\",\"original_title\":\"Avatar: The Way of Water\",\"overview\":\"Set more than a decade after the events of the first film, learn the story of the Sully family (Jake, Neytiri, and their kids), the trouble that follows them, the lengths they go to keep each other safe, the battles they fight to stay alive, and the tragedies they endure.\",\"popularity\":1000.602,\"poster_path\":\"/1yppMeTNQwDrzaUH4dRCx4mr8We.jpg\",\"release_date\":\"2022-12-14\",\"title\":\"Avatar: The Way of Water\",\"video\":false,\"vote_average\":0,\"vote_count\":0},{\"adult\":false,\"backdrop_path\":null,\"genre_ids\":[99],\"id\":287003,\"original_language\":\"en\",\"original_title\":\"Avatar: Scene Deconstruction\",\"overview\":\"The deconstruction of the Avatar scenes and sets\",\"popularity\":261.979,\"poster_path\":\"/uCreCQFReeF0RiIXkQypRYHwikx.jpg\",\"release_date\":\"2009-12-18\",\"title\":\"Avatar: Scene Deconstruction\",\"video\":false,\"vote_average\":9,\"vote_count\":3},{\"adult\":false,\"backdrop_path\":null,\"genre_ids\":[99],\"id\":111332,\"original_language\":\"en\",\"original_title\":\"Avatar: Creating the World of Pandora\",\"overview\":\"The Making-of James Cameron's Avatar. It shows interesting parts of the work on the set.\",\"popularity\":259.613,\"poster_path\":\"/d9oqcfeCyc3zmMal6eJbfj3gatc.jpg\",\"release_date\":\"2010-02-07\",\"title\":\"Avatar: Creating the World of Pandora\",\"video\":false,\"vote_average\":7,\"vote_count\":20}],\"total_pages\":3,\"total_results\":55}"
I convert this JSON to Class, thanks for the tip. This is my class now:
public class Result
{
public bool adult { get; set; }
public string backdrop_path { get; set; }
public List<int> genre_ids { get; set; }
public int id { get; set; }
public string original_language { get; set; }
public string original_title { get; set; }
public string overview { get; set; }
public double popularity { get; set; }
public string poster_path { get; set; }
public string release_date { get; set; }
public string title { get; set; }
public bool video { get; set; }
public double vote_average { get; set; }
public int vote_count { get; set; }
}
public class Root
{
public int page { get; set; }
public List<Result> results { get; set; }
public int total_pages { get; set; }
public int total_results { get; set; }
}
I would suggest you create a proper C# class to deserialize your JSON into. We can't see how you JSON looks, so I'll just give a simple example. Let's say this is your JSON:
{
"results": [
[
"foo",
"bar"
],
[
"baz",
"qux"
]
],
"someOtherField": "someValue"
}
If you go to https://json2csharp.com/ you can convert this into a C# class like this:
public class Root
{
public List<List<string>> results { get; set; }
public string someOtherField { get; set; }
}
To deserialize and access the data, you simply do the following (I'm using System.Text.Json instead of JavaScriptSerializer - see comment below):
var root = JsonSerializer.Deserialize<Root>(apiResponse);
// ...
List<string> listResult = root.results[0];
List<string> listResult2 = root.results[1];
// ...
LblTitle.Text = listResult[1]; // "bar"
LblTitle2.Text = listResult2[1]; // "qux"
Please refer to the definition of JavaScriptSerializer:
For .NET Framework 4.7.2 and later versions, use the APIs in the System.Text.Json namespace for serialization and deserialization. For earlier versions of .NET Framework, use Newtonsoft.Json.
See here for how to use System.Text.Json .
If you want to use Newtonsoft.Json instead, you should replace JsonSerializer.Deserialize with JsonConvert.DeserializeObject:
var root = JsonConvert.DeserializeObject<Root>(apiResponse);

How can I seed an enum by name from a Json file

I'm seeding data into my database on startup.
Problem - I want to seed the "YogaPose" by name, not number, as my YogaPose enum is really long (~150+) and trying to count the number is taking too long.
Question - Is this possible?
Here is what the code looks like to get the json data.
if (context.Poses.Any())
{
var posesData =
File.ReadAllText(path + #"/Data/SeedData/poses.json");
var poses = JsonSerializer.Deserialize<List<Pose>>(posesData);
foreach (var pose in poses)
{
context.Poses.Add(pose);
}
await context.SaveChangesAsync();
}
Here is a sample section from the json file, where you can see I'm using the YogaPose enum number. I want to use the name of the enum!
Attempt 1 - I tried using "YogaPose": "YogaPose.Crane" with a failure
Attempt 2 - I tried using "YogaPose": "Crane" with a failure
{
"YogaPose": 1,
"Description": "A compact arm balance, Crane Pose/Crow Pose, called Bakasana in Sanskrit, encourages toning in the abs and the arms, strengthening in the core, and improves focus in the mind.",
"Level": 2,
"YogaPoseTypes": [{"YogaType": 1}],
"Alias": "Crow",
"Icon": "fa fa-users",
"PreparatoryPoses": [{"YogaPose": 7},{"YogaPose": 44},{"YogaPose": 14},{"YogaPose": 122}],
"FollowUpPoses": [{"YogaPose": 5},{"YogaPose": 7}]
}
Here is the Pose entity
public class Pose : BaseEntity
{
public YogaPose YogaPose { get; set; }
public string Description { get; set; }
public YogaLevel Level { get; set; }
public ICollection<YogaPoseType> YogaPoseTypes { get; set; }
public string Sanskrit { get; set; }
public string Benefit { get; set; }
public string Alias { get; set; }
public string Icon { get; set; }
public ICollection<PreparatoryPose> PreparatoryPoses { get; set; }
public ICollection<FollowUpPose> FollowUpPoses { get; set; }
}
Here is a small section of the YogaPose enum
public enum YogaPose
{
[Display(Name = "Crane")]
Crane,
[Display(Name = "Dolphin")]
Dolphin
}
Yes, it's possible but depends on a json converter you are using (Newstonsoft or System.Text.Json). Please, have a look to the article: JsonConverter attributes.
You also should prepare another json input file with strings instead of numbers in the field "YogaPose", for example:
{
"YogaPose": "Crane",
"Description": "A compact arm balance, Crane Pose/Crow Pose, called Bakasana in Sanskrit, encourages toning in the abs and the arms, strengthening in the core, and improves focus in the mind.",
"Level": 2,
"YogaPoseTypes": [{"YogaType": 1}],
"Alias": "Crow",
"Icon": "fa fa-users",
"PreparatoryPoses": [{"YogaPose": 7},{"YogaPose": 44},{"YogaPose": 14},{"YogaPose": 122}],
"FollowUpPoses": [{"YogaPose": 5},{"YogaPose": 7}]
}

C# Deserialize JSON Object [duplicate]

This question already has answers here:
How to auto-generate a C# class file from a JSON string [closed]
(3 answers)
Closed 3 years ago.
I am attempting to deserialize a Json object that was returned from a web API with the structure as follows.
Here is my class structure in which the object is to be Deserialized into...
public class CandidateJson
{
public string response { get; set; }
//public string result { get; set; }
public Result result { get; set; }
public string Candidates { get; set; }
public List<row> rows { get; set; }
}
public class Result
{
public string result { get; set; }
public string uri { get; set; }
}
public class row
{
public string no { get; set; }
public List<FL> FL { get; set; }
}
public class FL
{
public string val { get; set; }
public string content { get; set; }
}
I am using the following line of code to Deserialized with no success....
var json = JsonConvert.DeserializeObject<CandidateJson>(JsonResult);
Upon execution of this line of code, I am prompted with the following error...
Unexpected character encountered while parsing value: {. Path 'response', line 1, position 13.
I would appreciate any assistance with this issue.
Please let me know if any additional information is needed.
Here is the raw JSON string:
{"response":{"result":{"Candidates":{"row":[
{"no":"1","FL":[{"val":"CANDIDATEID","content":"508304000012555617"},{"val":"Candidate ID","content":"ZR_129661_CAND"},{"val":"First Name","content":"PRODUCTION"},{"val":"Last Name","content":"TEST"},{"val":"Email","content":"patricia.conley#ampcorporate.com"},{"val":"Phone","content":"815-543-2109"},{"val":"Mobile","content":"815-555-5555"},{"val":"Street","content":"555 Test Ave"},{"val":"City","content":"DeKalb"},{"val":"State","content":"IL"},{"val":"Zip Code","content":"60115"},{"val":"SMCREATORID","content":"508304000000490014"},{"val":"Created By","content":"AMP Support IT Team"},{"val":"MODIFIEDBY","content":"508304000000227003"},{"val":"Modified By","content":"Nikki Bowman"},{"val":"Created Time","content":"2019-12-17 08:38:25"},{"val":"Updated On","content":"2019-12-20 15:23:10"},{"val":"Last Activity Time","content":"2019-12-20 15:23:10"},{"val":"SMOWNERID","content":"508304000000490014"},{"val":"Candidate Owner","content":"AMP Support IT Team"},{"val":"Source","content":"Non-Employee Referral"},{"val":"Email Opt Out","content":"false"},{"val":"Is Locked","content":"false"},{"val":"Is Unqualified","content":"false"},{"val":"Is Attachment Present","content":"false"},{"val":"Candidate Status","content":"Sales Training Scheduled"},{"val":"Career Page Invite Status","content":"0"},{"val":"Extension","content":"5555"},{"val":"Sales Training Date_ID","content":"508304000011808848"},{"val":"Sales Training Date","content":"2019-12-11 Digital Sales Training"},{"val":"Start Date","content":"2019-12-17"},{"val":"Candidate Job Category","content":"Print + Digital Outside"},{"val":"District Sales Manager","content":"Luke Wasowski"},{"val":"College Graduate","content":"false"},{"val":"Recruiter Initials","content":"NKB"},{"val":"Unit/Apt/Ste","content":"Apt 5"},{"val":"Hourly Rate","content":"5.00"},{"val":"Work State","content":"Illinois"},{"val":"Full Time/Part Time","content":"FTR"},{"val":"Work Email Address","content":"Nikki.Bowman#ampcorporate.com"},{"val":"EEO Class","content":"1.1"}]},
{"no":"2","FL":[{"val":"CANDIDATEID","content":"508304000011834365"},{"val":"Candidate ID","content":"ZR_125018_CAND"},{"val":"First Name","content":"Jennifer"},{"val":"Last Name","content":"Pedersen"},{"val":"Email","content":"jennyped248_hwo#indeedemail.com"},{"val":"Mobile","content":"+18157517187"},{"val":"City","content":"Genoa"},{"val":"State","content":"IL"},{"val":"Zip Code","content":"60135"},{"val":"Country","content":"United States"},{"val":"Experience in Years","content":"8"},{"val":"Current Employer","content":"WALMART"},{"val":"Current Job Title","content":"MOD TEAM MEMBER"},{"val":"Skill Set","content":"quick and exceptional customer experience, Helping and Advising Customers, Basic Word Processing, Communication Skills, Customer Service, Data Entry, Hard-Working, Intermediate Word Processing, Organisational Skills, Teamwork, Time Management, outstanding communication skills, Microsoft Word, Microsoft Excel, Microsoft Excel 2000, Microsoft Office, Microsoft Outlook, Microsoft PowerPoint, basic scheduling"},{"val":"SMCREATORID","content":"508304000000562001"},{"val":"Created By","content":"Matt Chenoweth"},{"val":"MODIFIEDBY","content":"508304000008810064"},{"val":"Modified By","content":"HR Department"},{"val":"Created Time","content":"2019-12-02 12:25:53"},{"val":"Updated On","content":"2019-12-12 09:04:51"},{"val":"Last Activity Time","content":"2019-12-12 09:04:51"},{"val":"SMOWNERID","content":"508304000000562001"},{"val":"Candidate Owner","content":"Matt Chenoweth"},{"val":"Source","content":"Indeed Resume"},{"val":"Email Opt Out","content":"false"},{"val":"Is Locked","content":"false"},{"val":"Is Unqualified","content":"false"},{"val":"Is Attachment Present","content":"true"},{"val":"Candidate Status","content":"Hired - AMP Office"},{"val":"Career Page Invite Status","content":"0"},{"val":"Source By","content":"Applied by Candidate"},{"val":"EMPID","content":"JFP147"},{"val":"Candidate Job Category","content":"Office - Digital Verification"},{"val":"College Graduate","content":"false"}]
}]}}
,"uri":"/recruit/private/json/Candidates/searchRecords"}}
I haven't tested it, but by the looks of it, your code should look like:
public class CandidateJson
{
public Response response { get; set; }
}
public class Response
{
public Result result { get; set; }
public string uri { get; set; }
}
public class Result
{
public Candidate Candidates { get; set; }
}
public class Candidate
{
public List<Row> row { get; set; }
}
public class Row
{
public string no { get; set; }
public List<FL> FL { get; set; }
}
public class FL
{
public string val { get; set; }
public string content { get; set; }
}
Note: You might want to use int or decimal instead of string for val and no, but there is not enough information for me to assert that.

How to index multiple blobs under a main record in Azure Search?

I followed the steps described on this tutorial. My case is a little bit different:
Instead of indexing Hotels and Rooms, I am indexing Candidates and Resumes.
Instead of using CosmosDB I am using an Azure SQL Database.
Following the tutorial, I am able to create the Index, the 2 Indexers (one for the SQL DB and one for the Blobs storage), and the 2 data sources.
The SQL DB contains all my candidates, and the storage contains all their resumes (files with PDF/DOC/DOCX formats). Each blob has a metadata "ResumeCandidateId" that contains the same value as the "CandidateId" for the Candidate.
I have the following fields for my Index:
[SerializePropertyNamesAsCamelCase]
public partial class Candidate
{
[Key]
[IsFilterable, IsRetrievable(true), IsSearchable]
public string CandidateId { get; set; }
[IsFilterable, IsRetrievable(true), IsSearchable, IsSortable]
public string LastName { get; set; }
[IsFilterable, IsRetrievable(true), IsSearchable, IsSortable]
public string FirstName { get; set; }
[IsFilterable, IsRetrievable(true), IsSearchable, IsSortable]
public string Notes { get; set; }
public ResumeBlob[] ResumeBlobs { get; set; }
}
[SerializePropertyNamesAsCamelCase]
public class ResumeBlob
{
[IsRetrievable(true), IsSearchable]
[Analyzer(AnalyzerName.AsString.StandardLucene)]
public string content { get; set; }
[IsRetrievable(true)]
public string metadata_storage_content_type { get; set; }
public long metadata_storage_size { get; set; }
public DateTime metadata_storage_last_modified { get; set; }
public string metadata_storage_name { get; set; }
[Key]
[IsRetrievable(true)]
public string metadata_storage_path { get; set; }
[IsRetrievable(true)]
public string metadata_content_type { get; set; }
public string metadata_author { get; set; }
public DateTime metadata_creation_date { get; set; }
public DateTime metadata_last_modified { get; set; }
public string ResumeCandidateId { get; set; }
}
As you can see, one Candidate can have multiple Resumes. The challenge is to populate the ResumeBlobs property...
The data from the SQL DB is indexed and mapped correctly by the Indexer. When I run the Blobs Indexer, it loads documents, however it does not map them and they never show up in the search (ResumeBlobs is always empty). Here is the code used to create the Blobs Indexer:
var blobDataSource = DataSource.AzureBlobStorage(
name: "azure-blob-test02",
storageConnectionString: "DefaultEndpointsProtocol=https;AccountName=yyy;AccountKey=xxx;EndpointSuffix=core.windows.net",
containerName: "2019");
await searchService.DataSources.CreateOrUpdateAsync(blobDataSource);
List<FieldMapping> map = new List<FieldMapping> {
new FieldMapping("ResumeCandidateId", "CandidateId")
};
Indexer blobIndexer = new Indexer(
name: "hotel-rooms-blobs-indexer",
dataSourceName: blobDataSource.Name,
targetIndexName: indexName,
fieldMappings: map,
//parameters: new IndexingParameters().SetBlobExtractionMode(BlobExtractionMode.ContentAndMetadata).IndexFileNameExtensions(".DOC", ".DOCX", ".PDF", ".HTML", ".HTM"),
schedule: new IndexingSchedule(TimeSpan.FromDays(1)));
bool exists = await searchService.Indexers.ExistsAsync(blobIndexer.Name);
if (exists)
{
await searchService.Indexers.ResetAsync(blobIndexer.Name);
}
await searchService.Indexers.CreateOrUpdateAsync(blobIndexer);
try
{
await searchService.Indexers.RunAsync(blobIndexer.Name);
}
catch (CloudException e) when (e.Response.StatusCode == (HttpStatusCode)429)
{
Console.WriteLine("Failed to run indexer: {0}", e.Response.Content);
}
I commented the parameters for the blobIndexer but I get the same results even if it's not commented.
When I run a search, here is an example of what I get:
{
"#odata.context": "https://yyy.search.windows.net/indexes('index-test01')/$metadata#docs(*)",
"value": [
{
"#search.score": 1.2127206,
"candidateId": "363933d1-7e81-4ed2-b82e-d7496d98db50",
"lastName": "LAMLAST",
"firstName": "ZFIRST",
"notes": "MGA ; SQL ; T-SQL",
"resumeBlobs": []
}
]
}
"resumeBlobs" is empty. Any idea how to do such a mapping?
AFAIK, Azure Search doesn't support a collection merge feature that seems to be necessary to implement your scenario.
An alternative approach to this is to create a separate index for resumes and point the resume indexer to that index. That means that some of your search scenarios will have to hit two indexes, but it's a path forward.

Parsing Json C#

I have a big problem parsing JSON in C# in Windows Phone 8 app.
The application close when I try to execute this part of the code. The problem append when the C# code deserialize json.
See below the code : C# (deserialization + class forms) and JSON result.
Thanks for your answers.
public partial class MyGrades : PhoneApplicationPage
{
string token = string.Empty;
string mail = string.Empty;
public class MyGradesJson
{
[JsonProperty("periods")]
public Periods periods { get; set; }
}
public class Periods
{
[JsonProperty("period")]
public List<Perioddata> perioddata { get; set; }
}
public class Perioddata
{
[JsonProperty("period")]
public Period period { get; set; }
// [JsonProperty("name")]
// public List disciplines { get; set; }
}
public class Period
{
[JsonProperty("id")]
public int id { get; set; }
[JsonProperty("name")]
public string name { get; set; }
[JsonProperty("start_date")]
public string start_date { get; set; }
[JsonProperty("end_date")]
public string end_date { get; set; }
}
HttpResponseMessage response = await httpClient.SendAsync(requestMessage);
string responseAsString = await response.Content.ReadAsStringAsync();
var resJson = JsonConvert.DeserializeObject<Periods>(responseAsString);
}
Here is the Json answer :
{
"periods":[
{
"period":{
"id":1,
"name":"Year 1",
"start_date":"2000-01-01",
"end_date":"2001-06-30"
},
"disciplines":[
{
"discipline":{
"id":6,
"name":"Potions"
},
"grades":[
{
"id":11,
"note":2,
"coefficient":2,
"assessment":"yolo",
"teacher":{
"id":2,
"user_id":4,
"login":"snape_se",
"name":"Snape, Severus"
}
},
{
"id":15,
"note":10,
"coefficient":1,
"assessment":"test",
"teacher":{
"id":2,
"user_id":4,
"login":"snape_se",
"name":"Snape, Severus"
}
}
]
}
]
}
]
}
I think your app is broken because your have null in your resJson.
The JSON you provided will not be deserialized into Perods object instance.
Try to generate C# classes from JSON. If this feature is not avaliable in your version of VS, try to use online tools. For example http://json2csharp.com/

Categories

Resources