I'm trying to deserialize json data formated in a way I haven't seen before.
I'm using json.net and C#.
The class corresponding to the json should be like this:
class Example
{
public Person[] data { get; set; }
}
class Person
{
public string Id { get; set; }
public string Nationality { get; set; }
public string Name { get; set; }
}
And this is how the json looks like:
{
data: {
"123": ["SWE", "Steve"],
"221": ["USA", "Bob"],
"245": ["CAN", "Susan"]
}
}
Is it possible using attributes or do I have to do it all myself?
Your variables on the data object (123, 221, 245) would a type List<string>().
With JSON.NET, your schema needs to match your data; types and names.
EDIT: Looking at your Person object, your POCO classes don't seem correct. You would need a structure like this:
public Data data { get; set; }
where data is...
public class Data
{
public List<string> 123 { get; set; }
...
}
Related
I am currently trying to learn to work with API systems using C# .net core 3 and Newtonsoft.
The following call to Steam API is what I am using
for specific game details. For example http://store.steampowered.com/api/appdetails?appids=72850
This returns JSON similar to this ( I have cut it down for simplicity )
{
"72850": {
"success": true,
"data": {
"type": "game",
"name": "The Elder Scrolls V: Skyrim",
"steam_appid": 72850,
"required_age": 0,
"is_free": false
}
}
}
Each return has the unique ID as the root in this case 72850 and I am at a loss on how to map this into an object class so I can process this data. The "data" element is what I am really interested in but as a beginner, I am at a loss.
This API indexes its response using the internal Identifier of the Item requested.
This is a common scenario and it's also a quite efficient method to organize objects based on an Indexer, which can then be used to store or retrieve these objects, from a database, for example.
A common way to deserialize JSON object indexed like this, is to use a Dictionary, where the Key is Indexer and the Value the RootObject of the class structure (the Model) that further describes the JSON properties.
Some notes on the current JSON:
The API looks like it's built to represent the JSON on a HTML document, since the internal strings are formatted ready for presentation on a HTML page. This can be less useful when used elsewhere and can also create a problem when deserializing.
I've added a trivial clean-up, replacing what can cause a problem for sure:
json = json.Replace(#"\/", "/").Replace(#"\t", "");
I've added some more properties and classes to those presented in the question: it may be useful to see when a JsonProperty attribute is needed and when is it's not. For example: the [JsonProperty("type")] attribute is added to the public string GameType { get; set; } property, since Type is a keyword that may be misinterpreted, as is Name etc.
Json.Net is not case sensitive, so the JSON property background can be assigned to a .Net property public Uri Background { get; set; } without problem.
A couple of WebSites that provide a free service to format, validate and convert JSON object to a class model:
JsonFormatter - Formatting, validation
QuickType - Multi-language Class Model generator
Download the JSON using the WebClient.DownloadString() method, clean up the JSON and deserialize:
var steamUri = new Uri("https://store.steampowered.com/api/appdetails?appids=72850")
string json = new WebClient(steamUri).DownloadString();
json = json.Replace(#"\/", "/").Replace(#"\t", "");
var steamObj = JsonConvert.DeserializeObject<Dictionary<long, SteamApps.SteamAppDetails>>(json);
Class structure:
public class SteamApps
{
public class SteamAppDetails
{
public bool Success { get; set; }
public Data Data { get; set; }
}
public class Data
{
[JsonProperty("type")]
public string GameType { get; set; }
[JsonProperty("name")]
public string GameName { get; set; }
[JsonProperty("steam_appid")]
public long SteamAppid { get; set; }
[JsonProperty("required_age")]
public long RequiredAge { get; set; }
[JsonProperty("is_free")]
public bool IsFree { get; set; }
[JsonProperty("short_description")]
public string ShortDescription { get; set; }
[JsonProperty("supported_languages")]
public string Languages { get; set; }
[JsonProperty("header_image")]
public string HeaderImage { get; set; }
public string WebSite { get; set; }
[JsonProperty("price_overview")]
public PriceOverview PriceOverview { get; set; }
public Dictionary<string, bool> Platforms { get; set; }
public List<Screenshot> Screenshots { get; set; }
public Uri Background { get; set; }
public List<Category> Categories { get; set; }
}
public class PriceOverview
{
public string Currency { get; set; }
public long Initial { get; set; }
public long Final { get; set; }
[JsonProperty("discount_percent")]
public decimal DiscountPercent { get; set; }
[JsonProperty("initial_formatted")]
public string InitialFormatted { get; set; }
[JsonProperty("final_formatted")]
public string FinalFormatted { get; set; }
}
public partial class Screenshot
{
[JsonProperty("id")]
public long Id { get; set; }
[JsonProperty("path_thumbnail")]
public string PathThumbnail { get; set; }
[JsonProperty("path_full")]
public string PathFull { get; set; }
}
public partial class Category
{
[JsonProperty("id")]
public long Id { get; set; }
[JsonProperty("description")]
public string Description { get; set; }
}
}
Since you only need the "Data" element from the json, it is fairly simple using Newtonsoft. First make a class with all the fields that the Data element contains as shown below:
public class Data
{
public string Type { get; set; }
public string Name { get; set; }
public long Steam_AppId { get; set; }
public int Required_Age { get; set; }
public bool Is_Free { get; set; }
}
Now in order to map the json response, which I'm assuming is stored in a string at the moment, you have to Deserialize it to map to your C# class. And you can do that very easily:
Edit: A more elegant solution which avoids all the string manipulation nuisance
//You already have this but I created it in order to test
string jsonResult = "{ \"72850\": " +
"{ \"success\": true, \"data\": " +
"{ \"type\": \"game\", \"name\": \"The Elder Scrolls V: Skyrim\", " +
"\"steam_appid\": 72850, \"required_age\": 0, \"is_free\": false } }";
//JObject is a class in Newtonsoft library for handling json objects
JObject jObject = JObject.Parse(jsonResult);
//Since you're sending a request to the api, either you already have the id
//"72850" or can extract it easily from uri. This line gets data's value
//by 1st searching for key = "72850" and then within that a key = "data"
JToken dataToken = jObject["72850"]["data"];
Data data = dataToken.ToObject<Data>();
Reference: https://www.newtonsoft.com/json/help/html/SerializingJSONFragments.htm
Older solution
//getting the value portion of data element/key
string jsonData = "{" + jsonResult.Substring(jsonResult.IndexOf("\"type"));
//removing the extra } from the end
jsonData = jsonData.TrimEnd('}');
//map the json string to a C# object
var dataObj = JsonConvert.DeserializeObject<Data>(jsonData);
So now you'll see the json values mapped to your Data object which in this case is dataObj. Feel free to ask questions if anything's not clear. Cheers!
I want to serialize/deserialize the following JSON:
{
"result": {
"ID": 1,
"TITLE": "Example",
"ARRAY": [
{
"Item1": "Result1",
"Item2": "Result2"
}
]
}
}
I tried with the following class format, but no sucess yet... Can someone help me deserialize it?
public class myClass
{
public string ID { get; set; }
[JsonProperty("TITLE")]
public string Name { get; set; }
}
obs.: Using the namespace Newtonsoft.JSON
In your example class definition above, you have called the class myClass but you would have had to call it result because ID and TITLE are members of the result JSON in the given example. myClass would not resolve to anything.
I don't know why you'd want to have a property called Name that is mapped to TITLE, but ok, if you want to do that you can modify the solution after you get it working.
Still, we're not done yet. You also have a JSON member called ARRAY and you need to define a separate class for that.
And still there is an additional problem: the result JSON is nested inside an implicit base object, so we need to define that as well. Let's call it BaseResult.
public class ARRAY
{
public string Item1 { get; set; }
public string Item2 { get; set; }
}
public class Result
{
public int ID { get; set; }
public string TITLE { get; set; }
public List<ARRAY> ARRAY { get; set; }
}
public class BaseResult
{
public Result result { get; set; }
}
If you are using Visual Studio, you can copy your JSON and paste it in any *.cs file with Edit > Paste Special > Paste JSON as Classes. It will generate POCO objects representing your JSON, which in your case will be this:
public class Rootobject
{
public Result result { get; set; }
}
public class Result
{
public int ID { get; set; }
public string TITLE { get; set; }
public ARRAY[] ARRAY { get; set; }
}
public class ARRAY
{
public string Item1 { get; set; }
public string Item2 { get; set; }
}
Then, asuming that you have your JSON in a string variable named data, you can deserialize it as follows:
var result= JsonConvert.DeserializeObject<Rootobject>(data);
I have some problem to deserialize JSON response from the RIOT API in C#. I want to get the list of "Champion" and the API return a stream like this :
{
"type":"champion",
"version":"6.1.1",
"data":{
"Thresh":{
"id":412,
"key":"Thresh",
"name":"Thresh",
"title":"the Chain Warden"
},
"Aatrox":{
"id":266,
"key":"Aatrox",
"name":"Aatrox",
"title":"the Darkin Blade"
},...
}
}
All data has the same attributes (id, key, name and title) so I create a champion class :
public class Champion
{
public int id { get; set; }
public string key { get; set; }
public string name { get; set; }
public string title { get; set; }
}
I need your help because i dont know how to deserialize this data... I need to create a Root class with type, version and data attributes (data is a list of champion)? I watched for used NewtonSoft Json but I dont found example who helped me.
You can use the following root object (more accurately Data Transfer Object) to retrieve the champions from the API. This will return all champions without having to create a class for each champion.
public class RootChampionDTO
{
public string Type { get; set; }
public string Version { get; set; }
public Dictionary<string, Champion> Data { get; set; }
}
then using Newtsonsoft's Json.NET, you would deserialize using the following:
JsonConvert.DeserializeObject<RootChampionDTO>(string json);
If you want to use NewtonSoft:
JsonConvert.DeserializeObject<RootObject>(string json);
Json .NET Documentation: http://www.newtonsoft.com/json/help/html/SerializingJSON.htm
Consider such classes:
public class ResponseModel
{
public string Type { get; set; }
public string Version { get; set; }
public Dictionary<string, Champion> Data { get; set; }
}
public class Champion
{
public int Id { get; set; }
public string Key { get; set; }
public string Name { get; set; }
public string Title { get; set; }
}
And after use Newtonsoft.Json nuget package to deserialize your json:
using Newtonsoft.Json;
var result = JsonConvert.DeserializeObject<ResponseModel>(json);
Note that Newtonsoft.Json default settings allow you to correctly parse camelCase properties from json into PascalCase properties in C# classes.
I have the following c# model object
public class AddressUserFields
{
public string number { get; set; }
public string street { get; set; }
public string apartment { get; set; }
public string city { get; set; }
public string state { get; set; }
public string zipcode { get; set; }
public string DPV { get; set; }
}
When I am trying to convert it to json string using json serialization method, it will convert like the following,
JSON string: {userFields:[{"number":null,"street":null,"apartment":"","city":null,"state":null,"zipcode":null,"DPV":null}]}
But actually I look for like the below,
Expected JSON result:
{userFields:[{"number":null},{"street":null},{"apartment":""},{"city":null},{"state":null},{"zipcode":null},{"DPV":null}]}
So could any one give the way to design my c# model object and get the expected json result.
You just have to create your poco objects in the structure your want the Json to be in.
If you want this structure:
{userFields:
[
{ "number":null,
"street":null,
"apartment":"",
"city":null,
"state":null,
"zipcode":null,
"DPV":null
}
]
}
This is an object with one property userFields of type AddressUserFields[].
So just add another class
public class SomeContainer
{
public AddressUserFields[] userFields {get;set;}
}
and serialize that one
If you really want an array of different objects which all have different properties, like what you posted:
...[{"number":null},{"street":null},{"apartment":""},...]
you can use an array of Dictionary<TKey,TValue>, like this:
public class Fields
{
public Dictionary<string, string>[] userFields { get; set; }
}
and use it like so?
var fields = new Fields()
{
userFields = new[]{
new Dictionary<string,string>(){{"number", null}},
new Dictionary<string,string>(){{"street", null}}
}
};
var json = JsonConvert.SerializeObject(fields);
So I have a problem with DeserializeObject with an json array and I cant find what I am doing wrong here:
{"name":"Pannbiff n\u00f6tf\u00e4rs stekt","number":1128,"nutrientValues":
{"energyKj":694,"energyKcal":166,"protein":17.2,"fat":7.6,"carbohydrates":7}}
My model looks like this:
And my code looks like:
var responseText = streamReader.ReadToEnd();
var jsonSerializer = JsonConvert.DeserializeObject(responseText);
public class Asware
{
public IEnumerable<NutrientValues> nutrientValues { get; set; }
}
public class NutrientValues
{
public int energyKcal { get; set; }
public double protein { get; set; }
public double carbohydrates { get; set; }
public int fat { get; set; }
}
Can't see what can be wrong here I have also tried:
JsonConvert.DeserializeObject>(responseText)
The problem here is that in your source JSON, nutrientValues is a single object, not an array of objects.
If you change your model as follows it should serialise correctly:
public class Asware
{
public NutrientValues nutrientValues { get; set; }
}
Alternatively, if you have control of the JSON, then you can modify it to contain an array of nutrients as follows, the [ ] characters indicate multiple items.
{"name":"Pannbiff n\u00f6tf\u00e4rs stekt","number":1128,"nutrientValues":
[{"energyKj":694,"energyKcal":166,"protein":17.2,"fat":7.6,"carbohydrates":7}]}