2

I am in search a method that deserializes an array (without member names) to a C# object. Working and expected examples are provided and I have seen many similar posts but not quite what I am looking for hence why felt to ask out for some assistance.

Do I need to take the approach of implementing custom deserialization or am I missing out something already existing?

    // Deserialize Works This Way
    public class Order
    {
        public string orderNo { get; set; }
        public string customerNo { get; set; }
        public List<List<double>> items { get; set; }
    }

    // Expected Covert Type.
    public class OrderExpected
    {
        public string orderNo { get; set; }
        public string customerNo { get; set; }
        public List<OrderItem> items { get; set; }
    }

    public class OrderItem
    {
        public int itemId { get; set; }
        public decimal price { get; set; }
        public decimal quantity { get; set; }
    }

Code I have tried and what I would like to get working:

     var json = "{\"orderNo\":\"AO1234\",\"customerNo\":\"C0129999\",\"items\":[[255, 1.65, 20951.60],[266, 1.80, 20000.00],[277, 1.90,0.50]]}";
     // Works OK, but ins't what I am after
     var order = JsonConvert.DeserializeObject<Order>(json);

     // I'd like to get some help to get this approch working.
     var orderexpected = JsonConvert.DeserializeObject<OrderExpected>(json);

Further information on items array: The items array is going to consist of arrays which have fixed length of 3 and values represent itemId, price and quantity respectively.

P.S. I am consuming an API which is out of my control.

Randi Ratnayake
  • 674
  • 9
  • 23
  • 2
    You almost definitely need a custom deserializer. https://www.newtonsoft.com/json/help/html/CustomJsonConverter.htm – SLaks Jan 29 '18 at 03:48
  • @SLaks Thanks. Seems that's obvious. I am on that path. Thank you for the prompt response. – Randi Ratnayake Jan 29 '18 at 04:23
  • 1
    You should be able to use `ObjectToArrayConverter` from [C# JSON.NET - Deserialize response that uses an unusual data structure](https://stackoverflow.com/a/39462464/3744182). In fact, this may be a duplicate. Agree? Alternatively, you could use a hardcoded `JsonConverter` like the one in [JSON deserialization - Map array indices to properties with JSON.NET](https://stackoverflow.com/a/36760064/3744182). – dbc Jan 29 '18 at 04:57

3 Answers3

4

this can help you..

public class OrderExpected
{
    public string orderNo { get; set; }
    public string customerNo { get; set; }
    public List<OrderItem> items { get; set; }
}

[JsonConverter(typeof(OrderItemConverter))]
public class OrderItem
{
    public int itemId { get; set; }
    public decimal price { get; set; }
    public decimal quantity { get; set; }
}

public class OrderItemConverter : JsonConverter
{

    public override bool CanConvert(Type objectType)
    {
        return objectType.Name.Equals("OrderItem");
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {

        JArray array =  JArray.Load(reader);
        return new OrderItem { 
            itemId = array[0].ToObject<int>(),
            price = array[1].ToObject<decimal>(),
            quantity = array[2].ToObject<decimal>()
        }; 
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var orderItem = value as OrderItem;
        JArray arra = new JArray();
        arra.Add(orderItem.itemId);
        arra.Add(orderItem.price);
        arra.Add(orderItem.quantity);
        arra.WriteTo(writer);
    }
}

using..

        string jsonString = "{\"orderNo\":\"AO1234\",\"customerNo\":\"C0129999\",\"items\":[[255, 1.65, 20951.60],[266, 1.80, 20000.00],[277, 1.90,0.50]]}";
        var objectResult = JsonConvert.DeserializeObject<OrderExpected>(jsonString);
        var serializationResult = JsonConvert.SerializeObject(objectResult);
        Console.WriteLine(serializationResult);
        // output : {"orderNo":"AO1234","customerNo":"C0129999","items":[[255,1.65,20951.6],[266,1.8,20000.0],[277,1.9,0.5]]}
levent
  • 3,464
  • 1
  • 12
  • 22
1

You can use custom JsonConverter for specified property by using attribute: JsonConverter(typeof(YourCustomConverter))

In your case simple examle should looks like this:

public class OrderExpected
{
    public string OrderNo { get; set; }
    public string CustomerNo { get; set; }
    [JsonConverter(typeof(OrderItemConverter))]
    public List<OrderItem> Items { get; set; }
}

public class OrderItemConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;

        var jArray = JArray.Load(reader);
        var result = new List<OrderItem>();
        foreach (var arrayItem in jArray)
        {
            var innerJArray = arrayItem as JArray;
            if(innerJArray?.Count != 3)
                continue;

            result.Add(new OrderItem
            {
                ItemId = (int) innerJArray[0],
                Price = (decimal)innerJArray[1],
                Quantity = (decimal)innerJArray[2]
            });
        }

        return result;
    }

    public override bool CanConvert(Type objectType)
    {
        throw new NotImplementedException();
    }
}

And deserialize your json as usual.

var obj = JsonConvert.DeserializeObject<OrderExpected>(json);
aleha_84
  • 8,309
  • 2
  • 38
  • 46
0

Alright, I agree with Levent. I just want to develop this answer! in Json.Net side use this attribute [JsonExtensionData] when Json string contains properties without property names

[Serializable]
[JsonObject]
public class Price
{
    [JsonExtensionData]
    public IDictionary<string, JToken> Values { get; set; }
    [JsonProperty("vendor")]
    public Dictionary<string, string> vendor { get; set; }
}
Hamit YILDIRIM
  • 4,224
  • 1
  • 32
  • 35