Search code examples
c#jsonrestjson.netjson-deserialization

REST API Response with property sometimes get a list or an object


I am calling the same REST API and from that API I am getting a response as a JSON object, and while trying to deserialize it, it throws an error because one of the objects sometimes returns as a list or an object.

I have shown some sample codes in which Address is sometimes returned as a list and sometimes as a single object.

JSON object which returns Address with list:

{
  "ResponseStatus": {
    "Code": "1",
    "Description": "Success"
  },
  "Address": [
    {
      "City": "CLEVELAND",
      "State": "OH",
      "PostalCode": "44126",
      "CountryCode": "US"
    },
    {
      "City": "CLEVELAND",
      "State": "WV",
      "PostalCode": "26215",
      "CountryCode": "US"
    }
  ]
}

JSON object which returns Address as an object:

{
  "ResponseStatus": {
    "Code": "1",
    "Description": "Success"
  },
  "Address": {
    "City": "CLEVELAND",
    "State": "OH",
    "PostalCode": "44126",
    "CountryCode": "US"
  }
}

The class I am using to deserialize the JSON object:

public class Address
{
    public string City { get; set; }
    public string State { get; set; }
    public string PostalCode { get; set; }
    public string CountryCode { get; set; }
}

public class ResponseStatus
{
    public string Code { get; set; }
    public string Description { get; set; }
}

public class Response
{
    public ResponseStatus ResponseStatus { get; set; }
    public List<Address> Address { get; set; }
}

Response result = JsonConvert.DeserializeObject<Response>(response);

Response: This variable is getting initialized after the REST API is called.


Solution

  • You should implement a Custom Json Converter to handle data with different types.

    With the below example, to handle the Address which possibly is an array or object.

    using Newtonsoft.Json;
    using Newtonsoft.Json.Linq;
    
    public class ObjectListConverter<T> : JsonConverter
        where T : class, new()
    {
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            JToken t = JToken.FromObject(value);
            t.WriteTo(writer);
        }
    
        public override List<T> ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            if (reader.TokenType == JsonToken.StartArray)
            {
                return JToken.Load(reader).ToObject<List<T>>();
            }
            else if (reader.TokenType == JsonToken.StartObject)
            {
                return new List<T> { JToken.Load(reader).ToObject<T>() };
            }
            else if (reader.TokenType == JsonToken.Null)
            {
                return null;
            }
            
            throw new JsonException();
        }
        
        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof(List<T>) || objectType == typeof(T);
        }
    }
    

    Add the ObjectListConverter into the JsonConverterAttribute.

    public class Response
    {
        public ResponseStatus ResponseStatus { get; set; }
        
        [JsonConverter(typeof(ObjectListConverter<Address>))]
        public List<Address> Address { get; set; }
    }