I am trying to create an abstraction layer for Json.NET deserialization using interfaces.
To achieve this I use custom JsonConverter which works just fine, until interfaces are introduced.
Following exception is thrown:
Unhandled Exception: Newtonsoft.Json.JsonSerializationException: Error setting value to 'Items' on 'BatchList'. ---> System.InvalidCastException: Unable to cast object of type 'System.Collections.Generic.List1[BatchItems]' to type 'System.Collections.Generic.List`1[IBatchItems]
This is the setup to repro in a console app:
class Program
{
    static void Main(string[] args)
    {
        var jsonBatch = @"{'items': [{'Id': 'name1','info': {'age': '20'}},{'Id': 'name2','info': {'age': '21'}}]}";
        DeserializeAndPost(jsonBatch);
    }
    public static void DeserializeAndPost(string json)
    {
        IBatchList req;
        req = JsonConvert.DeserializeObject<BatchList>(json);
        Post(req);
    }
    public static void Post(IBatchList batchList)
    {
        Console.WriteLine(batchList.Items.FirstOrDefault().Id);
    }
}
public interface IBatchList
{
    List<IBatchItems> Items { get; set; }
}
public interface IBatchItems
{
    string Id { get; set; }
    JObject Info { get; set; }
}
[JsonObject(MemberSerialization.OptIn)]
public class BatchList : IBatchList
{
    [JsonProperty(PropertyName = "Items", Required = Required.Always)]
    [JsonConverter(typeof(SingleOrArrayConverter<BatchItems>))]
    public List<IBatchItems> Items { get; set; }
}
[JsonObject]
public class BatchItems : IBatchItems
{
    [JsonProperty(PropertyName = "Id", Required = Required.Always)]
    public string Id { get; set; }
    [JsonProperty(PropertyName = "Info", Required = Required.Always)]
    public JObject Info { get; set; }
}
// JsonConverter
public class SingleOrArrayConverter<T> : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(List<T>));
    }
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JToken token = JToken.Load(reader);
        if (token.Type == JTokenType.Array)
        {
            return token.ToObject<List<T>>();
        }
        return new List<T> { token.ToObject<T>() };
    }
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        List<T> list = (List<T>)value;
        if (list.Count == 1)
        {
            value = list[0];
        }
        serializer.Serialize(writer, value);
    }
    public override bool CanWrite
    {
        get { return true; }
    }
}
I expect the output to be deserialized JSON as I provide the type for the interface to be used for deserialization:
 [JsonConverter(typeof(SingleOrArrayConverter<BatchItems>))]
to be used.
Instead, unhandled cast exception is being thrown.
Note that if I use instead SingleOrArrayConverter<IBatchItems>, I will get an exception
Newtonsoft.Json.JsonSerializationException: Could not create an instance of type
as the [JsonConverter(typeof(SingleOrArrayConverter<BatchItems>))] is meant to provide concrete type for the following interface: public List<IBatchItems> Items { get; set; }.
 
    