I'm trying to deserialize json that is sometimes array and some times objects (look on "Craftable"):
Dont look at the codes here i made a runable version to make that easier to understand the problem, please scroll down, tnx anyway :-)
Sometime this is an objects:
"prices": {
"5": {
"Tradable": {
"Craftable": {
"10": {
"currency": "earbuds",
"value": 4.5,
"last_update": 1404866151,
"difference": 76.95,
"value_high": 5
},
"11": {
"currency": "earbuds",
"difference": 7.0965,
"last_update": 1400430312,
"value": 1.8,
"value_high": 2.1
}
and sometimes it's an array with one cell:
"A Distinctive Lack of Hue": {
"defindex": [
5040
],
"prices": {
"6": {
"Tradable": {
"Craftable": [
{
"currency": "keys",
"value": 2,
"last_update": 1393465587,
"difference": 0.35275
}
]
I'm try to shove it into these classes:
public class Tradable
{
[JsonProperty("Craftable")]
[JsonConverter(typeof(CategoryConverter))]
public IDictionary<string, Craftable> Craftable { get; set; }
}
public class Craftable
{
public IDictionary<string, Priceindex> Priceindex { get; set; }
}
But I'm getting this exception:
Error setting value to 'Craftable' on 'SteamTrade.PriceSchema+Tradable'.
(e.InnerException).Message:
Unable to cast object of type 'Craftable' to type 'System.Collections.Generic.IDictionary`2[System.String,SteamTrade.PriceSchema+Craftable]'.
This is my convertor:
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JToken token = JToken.Load(reader);
if (token.Type == JTokenType.Object)
{
return token.ToObject<Craftable>();
}
else if (token.Type == JTokenType.Array)
{
return token.First.ToObject<Craftable>();
}
throw new JsonSerializationException("Unexpected token type: " + token.Type.ToString());
}
Other info which could help, the Priceindex class and the value inside the "token"when in side the convertor [I cant post the image cuz I don't have enough Rep, should i link it from outside website?]:
public class Priceindex
{
[JsonProperty("currency")]
public string currency { get; set; }
[JsonProperty("value")]
public decimal value { get; set; }
[JsonProperty("value_old")]
public Priceindex value_old { get; set; }
[JsonProperty("value_high")]
public string value_high { get; set; }
//[JsonProperty("value_raw")]
//public string currency { get; set; }
[JsonProperty("last_update")]
public int last_update { get; set; }
[JsonProperty("difference")]
public decimal difference { get; set; }
}
EDIT: To understande that scheme easier you can see "http://backpack.tf/api/prices"
RUNABLE CODE:
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using System.Net;
using System.IO;
using System.Threading;
using SteamTrade;
using Newtonsoft.Json.Linq;
namespace SteamTrade
{
/// <summary>
/// This class represents the TF2 Item prices schema from backpack.tf as deserialized from its
/// JSON representation.
/// </summary>
public class PriceSchema
{
/// <summary>
/// Fetches the Tf2 Item schema.
/// </summary>
/// <param name="apiKey">The API key.</param>
/// <returns>A deserialized instance of the Item Schema.</returns>
/// <remarks>
/// The schema will be cached for future use if it is updated.
/// </remarks>
[STAThread]
public static void Main(string[] args)
{
// Convert the Json
string result = File.ReadAllText("Json.txt");
Data schemaResult = JsonConvert.DeserializeObject<Data>(result);
}
public class Data
{
[JsonProperty("response")]
public Response response { get; set; }
}
public class Response
{
[JsonProperty("success")]
public int success { get; set; }
[JsonProperty("message ")]
public string message { get; set; }
[JsonProperty("current_time")]
public string current_time { get; set; }
[JsonProperty("raw_usd_value")]
public string raw_usd_value { get; set; }
[JsonProperty("usd_currency ")]
public string usd_currency { get; set; }
[JsonProperty("usd_currency_index")]
public int usd_currency_index { get; set; }
[JsonProperty("items")]
public IDictionary<string, ItemName> items { get; set; }
//public Items[] items { get; set; }
}
public class Items
{
public ItemName ItemName { get; set; }
}
public class ItemName
{
[JsonProperty("defindex")]
public int[] Defindex { get; set; }
[JsonProperty("prices")]
public IDictionary<string, QualityInteger> Prices { get; set; }
}
public class Prices
{
public QualityInteger QualityInteger { get; set; }
}
public class QualityInteger
{
public Tradable Tradable { get; set; }
public Untradable Untradable { get; set; }
}
public class Tradable
{
[JsonProperty("Craftable")]
[JsonConverter(typeof(CategoryConverter))]
public IDictionary<string, Craftable> Craftable { get; set; }
//public List<Craftable> craftable { get; set; }
[JsonProperty("Non-Craftable")]
public List<Uncraftable> Uncraftable { get; set; }
}
public class Untradable
{
[JsonProperty("Craftable")]
[JsonConverter(typeof(CategoryConverter))]
public Craftable Craftable { get; set; }
//public IDictionary<string, Craftable> Craftable { get; set; }
//public List<Craftable> craftable { get; set; }
[JsonProperty("Non-Craftable")]
public List<Uncraftable> Uncraftable { get; set; }
}
#region Overrdie Reader
class CategoryConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(string[]));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JToken token = JToken.Load(reader);
if (token.Type == JTokenType.Object)
{
return token.ToObject<Craftable>();
}
else if (token.Type == JTokenType.Array)
{
return token.First.ToObject<Craftable>();
}
throw new JsonSerializationException("Unexpected token type: " + token.Type.ToString());
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
#endregion
public class Craftable
{
//public List<Priceindex> Priceindex { get; set; }
public IDictionary<string, Priceindex> Priceindex { get; set; }
//public Priceindex Priceindex { get; set; }
}
public class Uncraftable
{
//public Priceindex Priceindex { get; set; }
public IDictionary<string, Priceindex> Priceindex { get; set; }
//public Priceindex Priceindex { get; set; }
}
public class Priceindex
{
[JsonProperty("currency")]
public string currency { get; set; }
[JsonProperty("value")]
public decimal value { get; set; }
[JsonProperty("value_old")]
public Priceindex value_old { get; set; }
[JsonProperty("value_high")]
public string value_high { get; set; }
//[JsonProperty("value_raw")]
//public string currency { get; set; }
[JsonProperty("last_update")]
public int last_update { get; set; }
[JsonProperty("difference")]
public decimal difference { get; set; }
}
}
}
and the text file contains an example: from here V:
{
"response": {
"success": 1,
"current_time": 1405635143,
"raw_usd_value": 0.245,
"usd_currency": "metal",
"usd_currency_index": 5002,
"items": {
"A Brush with Death": {
"defindex": [
30186
],
"prices": {
"6": {
"Tradable": {
"Craftable": [
{
"currency": "metal",
"value": 3.66,
"last_update": 1405098842,
"difference": -0.34
}
]
}
}
}
},
"A Rather Festive Tree": {
"defindex": [
341
],
"prices": {
"5": {
"Tradable": {
"Craftable": {
"10": {
"currency": "earbuds",
"value": 4.5,
"last_update": 1404866151,
"difference": 76.95,
"value_high": 5
},
"11": {
"currency": "earbuds",
"difference": 7.0965,
"last_update": 1400430312,
"value": 1.8,
"value_high": 2.1
},
}
}
"6": {
"Tradable": {
"Craftable": [
{
"currency": "metal",
"value": 1.66,
"last_update": 1400374538,
"difference": -0.17
}
],
"Non-Craftable": [
{
"currency": "metal",
"value": 1.33,
"last_update": 1400368707,
"difference": -0.22
}
]
}
}
}
},
}
}
}
end of file here^