3

I get the following JSON-Message as a return from a REST-API:

{
   "result":{
      "CONTACT":[
         102565, 
         523652
      ],
      "COMPANY":[
         30302
      ]
   }
}

for deserializing I use Newtonsoft.Json with the following classes:

public class DuplicateResponseBody {
    [JsonProperty("result")]
    public ContactCompany Result { get; set; }
}

public class ContactCompany {
    [JsonProperty("CONTACT")]
    public int[] ContactIds { get; set; }
    [JsonProperty("COMPANY")]
    public int[] CompanyIds { get; set; }
}

this is working without problems.

But when there are no values, the REST-Response looks like

{
   "result":[]
}

the result is not an array and the deserialization would not working anymore. I cannot change the REST-API.

Does someone have an Idea, how can I solve the problem on the deserialization-step?

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
BennoDual
  • 5,865
  • 15
  • 67
  • 153
  • 2
    Although there is a workaround (see answer given), I'd be straight onto the vendor of that API and ask them to return a valid response! – Jamiec Jun 27 '22 at 10:49
  • 1
    You could apply `[JsonConverter(typeof(JsonSingleOrEmptyArrayConverter))]` to `Result` where `JsonSingleOrEmptyArrayConverter` comes from [this answer](https://stackoverflow.com/a/29450279/3744182) to [Deserialize JSON when a value can be an object or an empty array](https://stackoverflow.com/q/29449641/3744182). In fact your question could be a duplicate, agree? – dbc Jun 27 '22 at 14:26
  • 1
    Does this answer your question? [JSON.NET Deserialization - Single Result vs Array](https://stackoverflow.com/questions/27047875/json-net-deserialization-single-result-vs-array) – Charlieface Jun 27 '22 at 14:39

2 Answers2

4

I don't think that you need any converters, it would be enough just to add a json constructor to your class

public class DuplicateResponseBody
{
    [JsonProperty("result")]
    public ContactCompany Result { get; set; }
    
    [Newtonsoft.Json.JsonConstructor]
    public  DuplicateResponseBody(JToken result)
    {
         if ( result.Type.ToString()!="Array")
         Result= result.ToObject<ContactCompany>();
    }

    public DuplicateResponseBody() {}
}
Serge
  • 40,935
  • 4
  • 18
  • 45
2

You could implement custom JsonConverter for that property and treat an array as null.

public class ContactCompanyConverter : JsonConverter<ContactCompany>
{
    public override ContactCompany ReadJson(
        JsonReader reader,
        Type objectType,
        ContactCompany existingValue,
        bool hasExistingValue,
        JsonSerializer serializer)
    {
        var token = JToken.Load(reader);
        return token.Type != JTokenType.Array ? token.ToObject<ContactCompany>() : null;
    }

    public override void WriteJson(
        JsonWriter writer,
        ContactCompany value,
        JsonSerializer serializer)
    {
        var token = JToken.FromObject(value);
        token.WriteTo(writer);
    }
}

In order to use the converter, just pass it through the JsonConverterAttribute on your property.

public class DuplicateResponseBody
{
    [JsonProperty("result")]
    [JsonConverter(typeof(ContactCompanyConverter))]
    public ContactCompany Result { get; set; }
}
msmolcic
  • 6,407
  • 8
  • 32
  • 56