3

I'm trying to Deserialize an array of array in c# but I keep getting errors here's the Json response

{
   "result":{
      "14400":[
         [
            1664006400,
            19121.92,
            19189,
            18925.94,
            18997.14,
            40878.7735,
            780289470.6555521
         ],
         [
            1664020800,
            18996.63,
            19002.18,
            18988.8,
            18997.46,
            153.341,
            2912907.7335217
         ]
      ],
      "180":[
         [
            1664006400,
            18998.8,
            19000.05,
            18990.05,
            18997.14,
            319.25744,
            6064375.6882797
         ],
         [
            1664006580,
            18996.63,
            19002.18,
            18988.8,
            18997.46,
            153.341,
            2912907.7335217
         ]
      ],
      "1800":[
         [
            1664006400,
            19003.15,
            19025.07,
            18968.11,
            18997.14,
            4823.42007,
            91655099.2502063
         ],
         [
            1664008200,
            18996.63,
            19002.18,
            18988.8,
            18997.46,
            153.341,
            2912907.7335217
         ]
      ],
      "21600":[
         [
            1664020800,
            19136.9,
            19164.25,
            18925.94,
            18997.46,
            20740.99979,
            394973767.0314926
         ]
      ],
      "300":[
         [
            1664006400,
            18984.59,
            19001.1,
            18980.28,
            18997.14,
            591.96318,
            11243452.571249
         ],
         [
            1664006700,
            18996.63,
            19002.18,
            18988.8,
            18997.46,
            153.341,
            2912907.7335217
         ]
      ],
      "3600":[
         [
            1664006400,
            19078.19,
            19084.27,
            18925.94,
            18997.14,
            11653.39145,
            221429662.3864255
         ],
         [
            1664010000,
            18996.63,
            19002.18,
            18988.8,
            18997.46,
            153.341,
            2912907.7335217
         ]
      ],
      "60":[
         [
            1664006400,
            18995.8,
            18999.1,
            18993.77,
            18997.14,
            106.13386,
            2016106.7154772
         ],
         [
            1664006460,
            18996.63,
            19002.18,
            18988.8,
            18997.46,
            153.341,
            2912907.7335217
         ]
      ],
      "7200":[
         [
            1664006400,
            19136.9,
            19164.25,
            18925.94,
            18997.14,
            20587.65879,
            392060859.2979709
         ],
         [
            1664013600,
            18996.63,
            19002.18,
            18988.8,
            18997.46,
            153.341,
            2912907.7335217
         ]
      ],
      "900":[
         [
            1664006400,
            19008.41,
            19017.63,
            18968.11,
            18997.14,
            2341.42806,
            44481574.1022888
         ],
         [
            1664007300,
            18996.63,
            19002.18,
            18988.8,
            18997.46,
            153.341,
            2912907.7335217
         ]
      ]
   },
   "allowance":{
      "cost":0,
      "remaining":10,
      "remainingPaid":9999999999,
      "account":"00000"
   }
}

I tried creating class for each array inside the result EX:

  public class Rootobject
    {
        public Result result { get; set; }
        public Allowance allowance { get; set; }
    }


    public class R_14400
    {
        [JsonProperty(Order = 1)]
        public long CloseTime { get; set; }
        [JsonProperty(Order = 2)]
        public decimal Open { get; set; }
        [JsonProperty(Order = 3)]
        public decimal High { get; set; }
        [JsonProperty(Order = 4)]
        public decimal Low { get; set; }
        [JsonProperty(Order = 5)]
        public decimal Close { get; set; }
        [JsonProperty(Order = 6)]
        public decimal Volume { get; set; }
        [JsonProperty(Order = 7)]
        public decimal QuoteVolume { get; set; }
    }

    public class R_60
    {
        [JsonProperty(Order = 1)]
        public long CloseTime { get; set; }
        [JsonProperty(Order = 2)]
        public decimal Open { get; set; }
        [JsonProperty(Order = 3)]
        public decimal High { get; set; }
        [JsonProperty(Order = 4)]
        public decimal Low { get; set; }
        [JsonProperty(Order = 5)]
        public decimal Close { get; set; }
        [JsonProperty(Order = 6)]
        public decimal Volume { get; set; }
        [JsonProperty(Order = 7)]
        public decimal QuoteVolume { get; set; }
    }

    public class Result
    {
        public R_14400 _14400 { get; set; }
        //public float[][] _180 { get; set; }
        //public float[][] _1800 { get; set; }
        //public float[][] _21600 { get; set; }
        //public float[][] _300 { get; set; }
        //public float[][] _3600 { get; set; }
        public R_60 _60 { get; set; }
        //public float[][] _7200 { get; set; }
        //public float[][] _900 { get; set; }

    }



    public class Allowance
    {
        public int cost { get; set; }
        public int remaining { get; set; }
        public long remainingPaid { get; set; }
        public string account { get; set; }
    }

and then tried to do the following

        public class ObjectToArrayConverter<T> : JsonConverter
    {
        //https://stackoverflow.com/a/39462464/3744182
        public override bool CanConvert(Type objectType)
        {
            return typeof(T) == objectType;
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            var objectType = value.GetType();
            var contract = serializer.ContractResolver.ResolveContract(objectType) as JsonObjectContract;
            if (contract == null)
                throw new JsonSerializationException(string.Format("invalid type {0}.", objectType.FullName));
            writer.WriteStartArray();
            foreach (var property in SerializableProperties(contract))
            {
                var propertyValue = property.ValueProvider.GetValue(value);
                if (property.Converter != null && property.Converter.CanWrite)
                    property.Converter.WriteJson(writer, propertyValue, serializer);
                else
                    serializer.Serialize(writer, propertyValue);
            }
            writer.WriteEndArray();
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            var contract = serializer.ContractResolver.ResolveContract(objectType) as JsonObjectContract;
            if (contract == null)
                throw new JsonSerializationException(string.Format("invalid type {0}.", objectType.FullName));

            if (reader.MoveToContentAndAssert().TokenType == JsonToken.Null)
                return null;
            if (reader.TokenType != JsonToken.StartArray)
                throw new JsonSerializationException(string.Format("token {0} was not JsonToken.StartArray", reader.TokenType));

            // Not implemented: JsonObjectContract.CreatorParameters, serialization callbacks, 
            existingValue = existingValue ?? contract.DefaultCreator();

            using (var enumerator = SerializableProperties(contract).GetEnumerator())
            {
                while (true)
                {
                    switch (reader.ReadToContentAndAssert().TokenType)
                    {
                        case JsonToken.EndArray:
                            return existingValue;

                        default:
                            if (!enumerator.MoveNext())
                            {
                                reader.Skip();
                                break;
                            }
                            var property = enumerator.Current;
                            object propertyValue;
                            // TODO:
                            // https://www.newtonsoft.com/json/help/html/Properties_T_Newtonsoft_Json_Serialization_JsonProperty.htm
                            // JsonProperty.ItemConverter, ItemIsReference, ItemReferenceLoopHandling, ItemTypeNameHandling, DefaultValue, DefaultValueHandling, ReferenceLoopHandling, Required, TypeNameHandling, ...
                            if (property.Converter != null && property.Converter.CanRead)
                                propertyValue = property.Converter.ReadJson(reader, property.PropertyType, property.ValueProvider.GetValue(existingValue), serializer);
                            else
                                propertyValue = serializer.Deserialize(reader, property.PropertyType);
                            property.ValueProvider.SetValue(existingValue, propertyValue);
                            break;
                    }
                }
            }
        }

        static IEnumerable<JsonProperty> SerializableProperties(JsonObjectContract contract)
        {
            return contract.Properties.Where(p => !p.Ignored && p.Readable && p.Writable);
        }
    }

and then Deserializing

var settings = new JsonSerializerSettings
{
    Converters = { new ObjectToArrayConverter<R_60>() },
};
var root = JsonConvert.DeserializeObject<List<R_60>>(JsonStr,settings);

I tried going through the Rootobject and then I tried using IList<IList> but nothing worked.

0

3 Answers 3

1

You could use Brian Rogers' solution to map a Json array items to a particular object's properties.

With that Attribute and Converter in your hand, you can define your model classes like these:

class Root
{
    public Dictionary<int, InnerMost[]> Result { get; set; }
    public Allowance Allowance { get; set; }
}

class Allowance
{
    public int Cost { get; set; }
    public int Remaining { get; set; }
    public long RemainingPaid { get; set; }
    public string Account { get; set; }
}

[JsonConverter(typeof(ArrayToObjectConverter<InnerMost>))] 
class InnerMost
{
    [JsonArrayIndex(0)]
    public long CloseTime { get; set; }
    [JsonArrayIndex(1)]
    public decimal Open { get; set; }
    [JsonArrayIndex(2)]
    public decimal High { get; set; }
    [JsonArrayIndex(3)]
    public decimal Low { get; set; }
    [JsonArrayIndex(4)]
    public decimal Close { get; set; }
    [JsonArrayIndex(5)]
    public decimal Volume { get; set; }
    [JsonArrayIndex(6)]
    public decimal QuoteVolume { get; set; }
}

and the usage will be this simple:

var result = JsonConvert.DeserializeObject<Root>(json);

UPDATE #1

Here you can find a working version: dotnet fiddle link.

Sign up to request clarification or add additional context in comments.

4 Comments

Thank you for the answer it didn't work it kept giving me an error "The given key was not present in the dictionary." I'm sure it's something wrong I did but your answer helped me in another place in the code so thank you very much
@Kha1ed I've tried my code with your example json and it worked fine. It is strange that it does not work on your side. I could put together a dotnetfiddle if you wish.
if it's not much work for you I'll be thankful to see an example in dotnetfiddle, thank you again
@Kha1ed I've updated my post with a dotnetfiddle link
0

So i saved your json in a file, then copied it and pasted it in Visual Studio as class: enter image description here

And Visual Studio created slightly different model from what you posted. But property names were ugly, like 14400 so i overcame it with adding attribute specifying name of JSON prop:

[JsonProperty("14400")]
public float[][] CloseTime { get; set; }

So I ended up with such classes (it's up to you to add correct maping in attributes, but for me that worked):

public class Rootobject
{
    public Result result { get; set; }

    public Allowance allowance { get; set; }
}

public class Result
{
    [JsonProperty("14400")]
    public float[][] CloseTime { get; set; }

    [JsonProperty("180")]
    public float[][] Open { get; set; }

    [JsonProperty("1800")]
    public float[][] High { get; set; }

    [JsonProperty("21600")]
    public float[][] Low { get; set; }

    [JsonProperty("300")]
    public float[][] Close { get; set; }

    [JsonProperty("3600")]
    public float[][] Volume { get; set; }

    [JsonProperty("60")]
    public float[][] QuoteVolume { get; set; }

    [JsonProperty("7200")]
    public float[][] _7200 { get; set; }

    [JsonProperty("900")]
    public float[][] _900 { get; set; }
}

public class Allowance
{
    public int cost { get; set; }

    public int remaining { get; set; }

    public long remainingPaid { get; set; }

    public string account { get; set; }
}

2 Comments

I think the OP is looking for something different. For example his/her R_14400 class represents an array item under the result.14400 field. As far as I understand the question :)
with slight changes I made it work with this answer thank you Michal, you were a big help to me :D
0

You could do something like this and then use the Newtonsoft.Json to deserialise it:

    using Newtonsoft.Json;
... 

Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(myJsonResponse);
public class Allowance
{
    public int cost { get; set; }
    public int remaining { get; set; }
    public long remainingPaid { get; set; }
    public string account { get; set; }
}

public class Result
{
    public List<List<double>> _14400 { get; set; }
    public List<List<double>> _180 { get; set; }
    public List<List<double>> _1800 { get; set; }
    public List<List<double>> _21600 { get; set; }
    public List<List<double>> _300 { get; set; }
    public List<List<double>> _3600 { get; set; }
    public List<List<double>> _60 { get; set; }
    public List<List<double>> _7200 { get; set; }
    public List<List<double>> _900 { get; set; }
}

public class Root
{
    public Result result { get; set; }
    public Allowance allowance { get; set; }
}

1 Comment

I kept getting the general error object reference not set to an instance But thank you for the effort I might have done something wrong

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.