I am deserializing JSON using Json.NET. How can I ignore a blank array that unexpectedly occurs inside an array of objects during deserializat
Json.NET will throw an exception when the expected JSON value type (object, array or primitive) does not match the observed type. In your case your JsonAppID
type corresponds to a JSON object - an unordered set of name/value pairs which begins with {
(left brace) and ends with }
(right brace). When an array is encountered instead the exception you see is thrown.
If you would prefer to silently skip invalid value types in an array of objects, you could introduce a custom JsonConverter for ICollection<T>
which does just that:
public class TolerantObjectCollectionConverter<TItem> : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return !objectType.IsArray && objectType != typeof(string) && typeof(ICollection<TItem>).IsAssignableFrom(objectType);
}
public override bool CanWrite { get { return false; } }
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)
{
// Get contract information
var contract = serializer.ContractResolver.ResolveContract(objectType) as JsonArrayContract;
if (contract == null || contract.IsMultidimensionalArray || objectType.IsArray)
throw new JsonSerializationException(string.Format("Invalid array contract for {0}", objectType));
// Process the first token
var tokenType = reader.SkipComments().TokenType;
if (tokenType == JsonToken.Null)
return null;
if (tokenType != JsonToken.StartArray)
throw new JsonSerializationException(string.Format("Expected {0}, encountered {1} at path {2}", JsonToken.StartArray, reader.TokenType, reader.Path));
// Allocate the collection
var collection = existingValue as ICollection<TItem> ?? (ICollection<TItem>)contract.DefaultCreator();
// Process the collection items
while (reader.Read())
{
switch (reader.TokenType)
{
case JsonToken.EndArray:
return collection;
case JsonToken.StartObject:
case JsonToken.Null:
collection.Add(serializer.Deserialize<TItem>(reader));
break;
default:
reader.Skip();
break;
}
}
// Should not come here.
throw new JsonSerializationException("Unclosed array at path: " + reader.Path);
}
}
public static partial class JsonExtensions
{
public static JsonReader SkipComments(this JsonReader reader)
{
while (reader.TokenType == JsonToken.Comment && reader.Read())
;
return reader;
}
}
Then apply it to your data model as follows:
public class JsonAppID
{
[JsonProperty(PropertyName = "count")]
public int Count { get; set; }
[JsonProperty(PropertyName = "term")]
public string Term { get; set; }
}
public class RootObject
{
[JsonProperty("total_events")]
public int TotalEvents { get; set; }
[JsonProperty("json.appID")]
[JsonConverter(typeof(TolerantObjectCollectionConverter<JsonAppID>))]
public List<JsonAppID> AppIds { get; set; }
[JsonProperty("unique_field_count")]
public int UniqueFieldCount { get; set; }
}
Sample working .Net fiddle.