0

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^

Brian Rogers
  • 125,747
  • 31
  • 299
  • 300
Remy
  • 1,053
  • 1
  • 19
  • 25
  • 3
    modify this public IDictionary Craftable { get; set; } to a public list Craftable. Ideally you would make your own classes for each object. Check out http://json2csharp.com/ to convert your json to c# objects – dsum27 Jul 19 '14 at 19:51
  • @dsum27 tnx for the respone, but as you can see in the example somethime the same "Craftable" field, my problem is with the convertor which is fail for some reason which i dont understand. and i already new the website you meantion but it giving errors while try solve that json "Parsing your JSON didn't work. Please make sure it's valid. Already did that? Please let me know so I can fix it." – Remy Jul 19 '14 at 20:00
  • I also pasted your json code in to convertion tool and I had to make a few modifications to fix the json, but then it worked. Fields that come up invalid you can change the name and add the [JsonProperty("What the invalid name is")] above the property. – dsum27 Jul 19 '14 at 20:07
  • @dsum27 i dont really understande you, thes above was example, the full json is this, " http://backpack.tf/api/IGetPrices/v4/?key=53c83fd84dd7b86a1d8b4567 " there is soo many name i cant hardcode them all, that reason im use IDictionary. – Remy Jul 19 '14 at 20:13
  • @dsum27 tnx, but i asked about the convertor that is fail somehow, not about my classes, i'll try to convert all the moudule to exe tomorrow and it's would be more readble. tnx for help mate. – Remy Jul 19 '14 at 20:27
  • This may be what you want then http://stackoverflow.com/questions/3142495/deserialize-json-into-c-sharp-dynamic-object/3806407#3806407 – dsum27 Jul 19 '14 at 20:45
  • Are you 100% sure you need typed schema? Looks like your schema is quite changable, maybe parse json to `dynamic` would be better solution? – Dima Jul 19 '14 at 22:40
  • @dsum27 i dont really like an dynamic, anyway, it hasnt work while i tried deseriale with dynamic. I adding now a code and text file that can be run from vs2012 (after you add reference to Newtonsoft.Json). it's will be up in a minute. – Remy Jul 20 '14 at 19:16
  • In one case Craftable is a dictionary, in another, it's an array. What is it? – Lasse V. Karlsen Jul 20 '14 at 20:43
  • @LasseV.Karlsen I dont know, and that is my problem! that's the reason i tried use convertor... – Remy Jul 21 '14 at 17:54
  • If that Json is correct, then you can't deserialize this into *strongly typed objects* because you don't have *strongly typed data*. You're going to have to deserialize it into a dynamic object or whatnot. – Lasse V. Karlsen Jul 21 '14 at 21:21

0 Answers0