Cannot deserialize the current JSON array - c#

First: I'm new to using JSON, and I used the answers on here to use Json.Net to deserialize data from a Pokemon API into a C# class (Pokemon class). I used http://json2csharp.com to help me define my class and it looks like this:
public class Pokemon
{
public Pokemon(string json)
{
JsonConvert.PopulateObject(json, this, PokeApi.JsonSerializerSettings);
}
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("evolutions")]
public Evolutions evolutions { get; set; }
[JsonProperty("national_id")]
public int national_id { get; set; }
}
with a bunch of other properties like resource_uri, attack stat, etc.
As the answer offered on the aforementioned link said, I used JsonConvert.DeserializeObject(json) like so:
public Pokemon GetPokemon(int nationalId)
{
using (WebClient client = new WebClient())
{
var json = client.DownloadString("http://pokeapi.co/api/v1/pokemon/" + nationalId + "/");
var output = JsonConvert.DeserializeObject<Pokemon>(json);
return output;
}
}
However I keep getting an exception that says "Cannot deserialize the current JSON array (e.g.[1,2,3]) into type 'Evolutions' because the type requires a JSON object..."
I found a lot of other questions asking the same exact thing, but I was confused with the top answers - sometimes the answer was to use JsonProperty, sometimes it was to use JsonConverter, without really an explanation on what all these meant. Do I need both?
Edit: sample json (call: http://pokeapi.co/api/v1/pokemon/1/)
{
"abilities": [
{
"name": "overgrow",
"resource_uri": "/api/v1/ability/1/"
},
{
"name": "chlorophyll",
"resource_uri": "/api/v1/ability/2/"
}
],
"attack": 49,
"catch_rate": 45,
"created": "2013-11-02T12:08:25.745455",
"defense": 49,
"egg_cycles": 21,
"egg_groups": [
{
"name": "Monster",
"resource_uri": "/api/v1/egg/1/"
},
{
"name": "Grass",
"resource_uri": "/api/v1/egg/8/"
}
],
"ev_yield": "1 Sp Atk",
"evolutions": {
"level": 16,
"method": "level up",
"resource_uri": "/api/v1/pokemon/2/",
"to": "Ivysaur"
},
"exp": 64,
"growth_rate": "ms",
"happiness": 70,
"height": "2'4",
"hp": 45,
"male_female_ratio": "87.5/12.5",
"modified": "2013-11-02T13:28:04.914889",
"moves": [
{
"learn_type": "other",
"name": "Tackle",
"resource_uri": "/api/v1/move/1/"
},
{
"learn_type": "other",
"name": "Growl",
"resource_uri": "/api/v1/move/2/"
},
{
"learn_type": "level up",
"level": 10,
"name": "Vine whip",
"resource_uri": "/api/v1/move/3/"
}
],
"name": "Bulbasaur",
"national_id": 1,
"resource_uri": "/api/v1/pokemon/4/",
"sp_atk": 65,
"sp_def": 65,
"species": "seed pokemon",
"speed": 45,
"total": 318,
"types": [
{
"name": "grass",
"resource_uri": "/api/v1/type/5/"
},
{
"name": "poison",
"resource_uri": "/api/v1/type/8/"
}
],
"weight": "15.2lbs"
}
Evolutions class:
public class Evolutions
{
public int level { get; set; }
public string method { get; set; }
public string resource_uri { get; set; }
public string to { get; set; }
}

I tried http://json2csharp.com/ with http://pokeapi.co/api/v1/pokemon/19/ and what I see is
public class RootObject
{
//...
public List<Evolution> evolutions { get; set; }
//...
}
This pretty mush is your Pokemon class. So you need to declare Evolutions as list.

Related

Create object of json when elements are variables

i need help for deserialize this json on C#.
{
"date": "2021-01-04T16:58:06-03:00",
"resultsInThisPage": 2,
"currentPage": 1,
"totalPages": 1,
"paymentOrders": {
"3AC525B8EF5F413D86CFDC9318E8B3F8": {
"code": "3AC525B8EF5F413D86CFDC9318E8B3F8",
"status": 5,
"amount": 3.00,
"grossAmount": 3,
"lastEventDate": "2021-01-04T16:54:36-03:00",
"schedulingDate": "2021-01-04T16:54:31-03:00",
"transactions": [
{
"code": "AF63C1B13EF14F318C51119CBE1E5CA4",
"date": "2021-01-04T16:54:32-03:00",
"status": 3
}
],
"discount": {
"type": "DISCOUNT_PERCENT",
"value": 0
}
},
"1E5A8F8D35D34938A12281BD45C62DBE": {
"code": "1E5A8F8D35D34938A12281BD45C62DBE",
"status": 1,
"amount": 3.00,
"grossAmount": 0,
"lastEventDate": "2021-01-04T16:54:33-03:00",
"schedulingDate": "2021-02-04T05:54:31-03:00",
"transactions": [],
"discount": {
"type": "DISCOUNT_PERCENT",
"value": 0
}
}
}
}
I´m trying use one Class for make this, but the elements of "paymentOrders" are variables.
How is the best way for do this?
I need create a object to manipulate these values.
paymentOrders would be a Dictionary<string,SomeObject> where SomeObject represents the object with all the properties like code, status etc
You can use Dictionary<string, SomeType> (or even Dictionary<Guid, SomeType> in your case, based on provided sample) to represent dynamic property names for paymentOrders json object. Something like this should do the trick:
public class Root {
// your dynamic prop
public Dictionary<string, PaymentOrder> paymentOrders { get; set; }
public DateTime date { get; set; }
// ... the rest o properties
}
public class PaymentOrder {
public string code { get; set; }
public int status { get; set; }
// ... the rest o properties
}

How do I deserialize a tree of objects into a DTO?

I am attempting to deserialize a tree of JSon objects I get back into a DTO. The tree can be up to 4 levels deep, and over 1200 nodes. The code is C# using Newtonsoft.Json for deserialization.
EDIT
The JSon looks like:
[
{
"id": 1095,
"name": "Item1-1",
"children": [
{
"id": 1097,
"name": "Item2-2",
"children": [
{
"id": 18,
"name": "Item3-3",
"children": [
{
"id": 19,
"name": "Item4-4",
"children": [],
"level": 4,
"parentId": 18
},
{
"id": 20,
"name": "Item5-4",
"children": [],
"level": 4,
"parentId": 18
}
],
"level": 3,
"parentId": 1097
}
],
"level": 2,
"parentId": 1095
}
],
"level": 1,
"parentId": null
}
]
My DTO is similar to this:
public class MyDTO
{
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("children")]
public MyDTO[] Children { get; set; }
[JsonProperty("level")]
public int Level { get; set; }
[JsonProperty("parentId")]
public int ParentId { get; set; }
public MyDTO()
{
}
}
I like Brian Rogers' solution in this link, which deserializes the json into objects:
How do I use JSON.NET to deserialize into nested/recursive Dictionary and List?
public static class JsonHelper
{
public static object Deserialize(string json)
{
return ToObject(JToken.Parse(json));
}
private static object ToObject(JToken token)
{
switch (token.Type)
{
case JTokenType.Object:
return token.Children<JProperty>()
.ToDictionary(prop => prop.Name,
prop => ToObject(prop.Value));
case JTokenType.Array:
return token.Select(ToObject).ToList();
default:
return ((JValue)token).Value;
}
}
}
I call the JSonHelper with object obj = JsonHelper.Deserialize(jsonString);
I have been experimenting with converting this code into a method to convert to MyDTO, but I keep running into compiler errors. I have attempted to simply convert the JValue casts with MyDTO and move on to the List with a List.
My goal is to call MyDTO obj = JsonHelp.Deserialize(jsonString) and get the tree of MyDTO objects back. Is it possible to do what I am trying, or should I find a way to cast each object to MyDTO?
First your JSON is missing a brakcet ], then your model needs a nullable parentId. Making a couple simple changes you can then you JsonConvert.DeserializeObject<IEnumerable<MyDTO>>(json).
So your JSON should look like this:
[
{
"id": 1095,
"name": "Item1-1",
"children": [
{
"id": 1097,
"name": "Item2-2",
"children": [
{
"id": 18,
"name": "Item3-3",
"children": [
{
"id": 19,
"name": "Item4-4",
"children": [],
"level": 4,
"parentId": 18
},
{
"id": 20,
"name": "Item5-4",
"children": [],
"level": 4,
"parentId": 18
}
],
"level": 2,
"parentId": 1095
}],
}],
"level": 1,
"parentId": null
}
]
And can be deserialized with this model:
public class MyDTO
{
public int Id { get; set; }
public string Name { get; set; }
public MyDTO[] Children { get; set; }
public int Level { get; set; }
public int? ParentId { get; set; }
}
Using this code:
var dto = JsonConvert.DeserializeObject<IEnumerable<MyDTO>>(json);

Converting JSON object to dictionary

I'm calling the ethplorer.io api, and it returns the below json. I have generated the classes in visual studio via 'paste special -> paste json as classes'. My problem is that Tokeninfo declares price as an object, this is because it can either be false if it has no price information, or a dictionary if it has values. While I have successfully deserialised the response using JsonConvert.DeserializeObject(rawJSON), I’m struggling to convert price in to c# dictionary if it has values.
public class Tokeninfo
{
public string address { get; set; }
public string name { get; set; }
public object decimals { get; set; }
public string symbol { get; set; }
public string totalSupply { get; set; }
public string owner { get; set; }
public long lastUpdated { get; set; }
public int issuancesCount { get; set; }
public int holdersCount { get; set; }
public object price { get; set; }
public string description { get; set; }
public float totalIn { get; set; }
public float totalOut { get; set; }
}
JSON response:
{
"address": "0xd8f41f341afe2c411b21b3f96263c6584b69baeb", //Not my address
"ETH": {
"balance": 762.13611095505,
"totalIn": 1040.0907032491,
"totalOut": 277.954592294
},
"countTxs": 22,
"tokens": [
{
"tokenInfo": {
"address": "0x355a458d555151d3b27f94227960ade1504e526a",
"name": "StockChain Coin",
"decimals": "18",
"symbol": "SCC",
"totalSupply": "10000000000000000000000000000",
"owner": "0x",
"lastUpdated": 1524401998,
"issuancesCount": 0,
"holdersCount": 86520,
"price": {
"rate": "0.0531126",
"diff": 4.8,
"diff7d": 19.82,
"ts": "1524400762",
"marketCapUsd": null,
"availableSupply": null,
"volume24h": "622004.0",
"currency": "USD"
}
},
"balance": 5000000000000000000,
"totalIn": 0,
"totalOut": 0
},
{
"tokenInfo": {
"address": "0xb679afd97bcbc7448c1b327795c3ef226b39f0e9",
"name": "Win Last Mile",
"decimals": "6",
"symbol": "WLM",
"totalSupply": "2000000000000000",
"owner": "0x8e7a75d5e7efe2981ac06a2c6d4ca8a987a44492",
"lastUpdated": 1524362946,
"issuancesCount": 0,
"holdersCount": 10945,
"price": false
},
"balance": 66000000,
"totalIn": 0,
"totalOut": 0
},
{
"tokenInfo": {
"address": "0xae66d00496aaa25418f829140bb259163c06986e",
"name": "Super Wallet Token",
"decimals": "8",
"symbol": "SW",
"totalSupply": "8400000000000000",
"owner": "0xba051682e9dbc40730fcef4a374e3a57a0ce3eff",
"lastUpdated": 1524401948,
"issuancesCount": 0,
"holdersCount": 30276,
"price": false
},
"balance": 11567900,
"totalIn": 0,
"totalOut": 0
},
{
"tokenInfo": {
"address": "0x8e4fbe2673e154fe9399166e03e18f87a5754420",
"name": "Universal Bonus Token | t.me/bubbletonebot",
"decimals": "18",
"symbol": "UBT",
"totalSupply": "1150000000000000000000000",
"owner": "0xc2db6e5b96dd22d9870a5ca0909cceac6604e21d",
"lastUpdated": 1524393745,
"issuancesCount": 0,
"holdersCount": 99896,
"price": false
},
"balance": 10000000000000000000,
"totalIn": 0,
"totalOut": 0
}
]
}
You need a custom deserializer to do what you want. It should be straight forward though. Here is some code which checks if the price is not false and then turns it into a Dictionary<string, string>. This code makes the assumption that your root object is named RootObject:
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var jsonObject = JObject.Load(reader);
var root = default(Rootobject);
// Let's go through each tokenInfo and check if price is not false
// so we can turn it into a dictionary.
foreach (var thisToken in root.tokens)
{
if (thisToken.tokenInfo.price.ToString() != "false")
{
thisToken.tokenInfo.price = JsonConvert.DeserializeObject<Dictionary<string, string>>(thisToken.tokenInfo.price.ToString());
}
}
serializer.Populate(jsonObject.CreateReader(), root);
return root;
}
Please see the full example here and search for ProfessionConverter in that link for the full class.
I think it is not very good approach to use false in cases when there is no price. If there is no price it should be something like "price" :{} or price element shouldn't be there at all. In other words, it is not good idea to mixup boolean object and dictionaty imho.
I think you can use provided by VisualStudio class where Price is an object. And you can create a custom serializer which will treat false as an null (or object with empty fields) along with standart deserialization mechanism.

JSON Deserialization C#

I'm trying to parse out some information I've retrieved from RottenTomatoes that's in a JSON format
{
"cast": [
{
"id": "162655641",
"name": "Tom Hanks",
"characters": [
"Woody"
]
},
{
"id": "162655909",
"name": "Tim Allen",
"characters": [
"Buzz Lightyear"
]
},
{
"id": "162655020",
"name": "Joan Cusack",
"characters": [
"Jessie the Cowgirl"
]
},
{
"id": "162672460",
"name": "Ned Beatty",
"characters": [
"Lots-o'-Huggin' Bear",
"Lotso"
]
},
{
"id": "162657445",
"name": "Richard Kind",
"characters": [
"Bookworm"
]
},
{
"id": "162654813",
"name": "Erik von Detten",
"characters": [
"Sid"
]
},
{
"id": "770713272",
"name": "James Anthony Cotton",
"characters": []
}
],
"links": {
"rel": "http://api.rottentomatoes.com/api/public/v1.0/movies/770672122.json"
}
}
I'm just trying to get this code to work but I'm getting an InvalidOperationException and this error
"Type 'System.String' is not supported for deserialization of an array."
Here's my code in main
string json = File.ReadAllText("json.txt");
CastInfo castMember = new JavaScriptSerializer().Deserialize<CastInfo>(json);
Here are my classes
public class CastInfo
{
public List<CustomCastInfo> cast { get; set; }
}
public class CustomCastInfo
{
public string id { get; set; }
public string name { get; set; }
public List<string> characters { get; set; }
}
And advice? And I realize I need to do something about the "links" in the bottom, but even when I delete that it still doesn't work.
I just tried running this with the json you provided and it worked fine.
using System.Collections.Generic;
using System.IO;
using System.Web.Script.Serialization;
namespace JsonDeserialization
{
class Program
{
static void Main(string[] args)
{
string json = File.ReadAllText("json.txt");
CastInfo castMember = new JavaScriptSerializer().Deserialize<CastInfo>(json);
}
}
public class CastInfo
{
public List<CustomCastInfo> cast { get; set; }
}
public class CustomCastInfo
{
public string id { get; set; }
public string name { get; set; }
public List<string> characters { get; set; }
}
}

SerializationException: End element 'caption' from namespace '' expected

I'm trying to deserialize a json string and I'm getting the error End element 'caption' from namespace '' expected. Found element 'created_time' from namespace ''. when calling
InstagramObject test = (InstagramObject) instagramObject.ReadObject(instagramWebResponse.GetResponseStream());
The json from Instagram returns many elements but there are only a few that I need. My DataContract will be posted below.
Basically I need {data:[{caption: string, link: string, images: {...}}]}
Here's an example of the json...
{
"data": [{
"comments": {
"data": [],
"count": 0
},
"caption": {
"created_time": "1296710352",
"text": "Inside le truc #foodtruck",
"from": {
"username": "kevin",
"full_name": "Kevin Systrom",
"type": "user",
"id": "3"
},
"id": "26621408"
},
"likes": {
"count": 15,
"data": [{
"username": "mikeyk",
"full_name": "Mike Krieger",
"id": "4",
"profile_picture": "..."
}, {...subset of likers...}]
},
"link": "http://instagr.am/p/BWrVZ/",
"user": {
"username": "kevin",
"profile_picture": "http://distillery.s3.amazonaws.com/profiles/profile_3_75sq_1295574122.jpg",
"id": "3"
},
"created_time": "1296710327",
"images": {
"low_resolution": {
"url": "http://distillery.s3.amazonaws.com/media/2011/02/02/6ea7baea55774c5e81e7e3e1f6e791a7_6.jpg",
"width": 306,
"height": 306
},
"thumbnail": {
"url": "http://distillery.s3.amazonaws.com/media/2011/02/02/6ea7baea55774c5e81e7e3e1f6e791a7_5.jpg",
"width": 150,
"height": 150
},
"standard_resolution": {
"url": "http://distillery.s3.amazonaws.com/media/2011/02/02/6ea7baea55774c5e81e7e3e1f6e791a7_7.jpg",
"width": 612,
"height": 612
}
},
"type": "image",
"filter": "Earlybird",
"tags": ["foodtruck"],
"id": "22721881",
"location": {
"latitude": 37.778720183610183,
"longitude": -122.3962783813477,
"id": "520640",
"street_address": "",
"name": "Le Truc"
}
}]
}
and here's my DataContract...
[DataContract]
public class InstagramObject {
[DataMember(Name = "data")]
public IEnumerable<InstagramData> instagramData { get; set; }
}
[DataContract]
public class InstagramData {
[DataMember(Name = "images")]
public List<InstagramImage> instagramImages { get; set; }
[DataMember(Name = "caption")]
public string caption { get; set; }
[DataMember(Name = "link")]
public string link { get; set; }
}
[DataContract]
public class InstagramImage {
[DataMember(Name = "low_resolution")]
public InstagramImageInfo lowResolutionImage { get; set; }
[DataMember(Name = "thumbnail")]
public InstagramImageInfo thumbnail { get; set; }
[DataMember(Name = "standard_resolution")]
public InstagramImageInfo standardResolution { get; set; }
}
[DataContract]
public class InstagramImageInfo {
[DataMember(Name = "url")]
public string url { get; set; }
[DataMember(Name = "width")]
public int width { get; set; }
[DataMember(Name = "height")]
public int height { get; set; }
}
In the data contract caption is declared as a string, but in the JSON caption is a record with various fields - caption should be declared to be an object with a compatible structure:
[DataContract]
public class InstagramCaption {
[DataMember(Name = "text")]
public string Text {get; set;}
}
. . .
[DataMember(Name = "caption")]
public InstagramCaption caption { get; set; }
. . .
No need to declare those clases If you want to go with Json.Net + Linq
var obj = (JObject)JsonConvert.DeserializeObject(json);
var result = obj["data"]
.Select(x => new {
Caption = (string)x["caption"]["text"],
Link = (string)x["link"],
Images = x["images"].Children()
.Select(y=>(string)y.First()["url"]).ToArray()
})
.ToArray();

Categories