0

I'm trying to parse an object response from a web API that I have no control

So, one of the responses is like this:

{
    "BatchID": 25,
    "Results": [{
        "ItemID": 123,
        "ResultMessage": "COMPLETED"
    }, {
        "ItemID": 456,
        "ResultMessage": "COMPLETED"
    }],
    "COMPLETED_COUNT": 2,
    "INPROGRESS_COUNT": 0,
    "FAILED_COUNT": 0
}

This is very easy to parse using NewtonSoft Json library; however I have encounter this as well:

{
    "3305": "COMPLETE",
    "7305": "COMPLETE",
    "COMPLETED_COUNT": 2,
    "INPROGRESS_COUNT": 0,
    "FAILED_COUNT": 0
}

I have no idea how many int properties I may encounter. In this example are only two "3305" and "7305"

My question is: is there a way I can create an object that can hold every integer in that response?

Thanks for your help.

Peter Szekeli
  • 2,712
  • 3
  • 30
  • 44
Pipo
  • 3
  • 2
  • 3
    Deserialize it as a `Dictionary`, otherwise you probably need to deserialize one or two properties into a known structure, classify which specific structure the rest must have depending on these properties and then deserialize again when you know the type to deserialize into. – Lasse V. Karlsen Nov 06 '17 at 12:59
  • Also check [this question](https://stackoverflow.com/questions/15253875/deserialize-json-with-known-and-unknown-fields) which shows how to support both known properties as well as unknown properties without having everything in the "unknown" set. – Lasse V. Karlsen Nov 06 '17 at 13:03
  • Also be aware that while the keys here have digits in them, they are still strings. The fact that those strings contain numbers may be something you know to be true for all those extra properties but I would still handle them purely as strings. – Lasse V. Karlsen Nov 06 '17 at 13:04
  • Thanks I'll give this a try and let you know. – Pipo Nov 06 '17 at 13:10
  • @LasseVågsætherKarlsenThanks for your tip. It worked very well. How can I mark your comment as solved? – Pipo Nov 07 '17 at 15:16

2 Answers2

1

You may want to try cast JSON acquired from API to the instance of JObject. It holds all properties with names & values

Nick Reshetinsky
  • 447
  • 2
  • 13
0

To define a type that will deserialize the given json into a type that mimicks the known structure + some unknown structure, use Json.Net and use this type:

public class Response
{
    [JsonProperty("COMPLETED_COUNT")]
    public int CompletedCount { get; set; }

    [JsonProperty("INPROGRESS_COUNT")]
    public int InProgressCount { get; set; }

    [JsonProperty("FAILED_COUNT")]
    public int FailedCount { get; set; }

    [JsonExtensionData]
    public Dictionary<string, object> ExtraData { get; } = new Dictionary<string, object>();
}

Please know that the "Results" sub-property in the first json will be difficult to handle in this concept, so you should still strive to make a "detection" algorithm that looks at a subset of the properties, and if some specific key properties exists, pick a different and more correct type to deserialize the json into.

For instance, here is a simple such heuristics:

public static ResponseBase Classify(string json)
{
    var response = JsonConvert.DeserializeObject<ResponseBase>(json);

    if (response.ExtraData.ContainsKey("Results"))
        return JsonConvert.DeserializeObject<ResponseWithResults>(json);

    return response;
}

public class ResponseBase
{
    [JsonProperty("COMPLETED_COUNT")]
    public int CompletedCount { get; set; }

    [JsonProperty("INPROGRESS_COUNT")]
    public int InProgressCount { get; set; }

    [JsonProperty("FAILED_COUNT")]
    public int FailedCount { get; set; }

    [JsonExtensionData]
    public Dictionary<string, object> ExtraData { get; } = new Dictionary<string, object>();
}

public class ResponseWithResults : ResponseBase
{
    public int BatchId { get; set; }
    public List<ResponseResult> Results { get; } = new List<ResponseResult>();
}

public class ResponseResult
{
    public int ItemId { get; set; }
    public string ResultMessage { get; set; }
}

Do note that this deserializes the json twice. There are different ways to handle/avoid that but you will have to decide if this is a valid way forward.

Lasse V. Karlsen
  • 380,855
  • 102
  • 628
  • 825