Q:

How to deserialize JSON with Json.Net and Xamarin with SubTypes?

I'm trying to deserialize this json:
{
  "teaser": [{
              "id": "...",
              "type": "category",
              "url": "https:...",
            },{
              "id": "...",
              "type": "brand",
              "url": "https:...",
              "videoCount": 1,
            },{
              "id": "...",
              "type": "video",
              "url": "https:...",
              "headline": "...",
            }]
}

It has a list of teasers whereby each teaser is different depending on its type. 
These would be my objects:
public class StartPage
{
        public IList<Teaser> Teaser { get; set; }
}

public abstract class Teaser
{
        public string Id { get; set; }
        public string Url { get; set; }
}

public class Video : Teaser
{
        public string Headline { get; set; }
}

public class Brand : Teaser
{
        public int VideoCount { get; set; }
}

I am new to Json.NET and Xamarin and couldn't find a solution for this case yet. Before, when I was using Android Studio and Gson, I could register sybtypes the following way:
RuntimeTypeAdapterFactory<Teaser> teaserRuntimeTypeAdapterFactory = RuntimeTypeAdapterFactory.of(
                Teaser.class, "type")
                .registerSubtype(Video.class, Teaser.TYPE_VIDEO)
                .registerSubtype(Brand.class, Teaser.TYPE_BRAND)
                .registerSubtype(Category.class, Teaser.TYPE_CATEGORY);

        return new GsonBuilder()
                .registerTypeAdapterFactory(teaserRuntimeTypeAdapterFactory);

Is there a similar way to achieve what I want with Json.NET I have overlooked yet?

A:

What you can do is create custom JsonConverter  please below snippet and find this dot net fiddle
string json ="{ 'Teaser': [{ 'id': '...', 'type': 'category', 'url': 'https:...', },{ 'id': '...', 'type': 'brand', 'url': 'https:...', 'videoCount': 1, },{ 'id': '...', 'type': 'video', 'url': 'https:...', 'headline': '...', }]}";

var list = JsonConvert.DeserializeObject<StartPage>(json);

public class BaseSpecifiedConcreteClassConverter : DefaultContractResolver
    {
        protected override JsonConverter ResolveContractConverter(Type objectType)
        {
            if (typeof(Teaser).IsAssignableFrom(objectType) && !objectType.IsAbstract)
                return null; // pretend TableSortRuleConvert is not specified (thus avoiding a stack overflow)
            return base.ResolveContractConverter(objectType);
        }
    }

public class BaseConverter : JsonConverter
    {
        static JsonSerializerSettings SpecifiedSubclassConversion = new JsonSerializerSettings() { ContractResolver = new BaseSpecifiedConcreteClassConverter() };

        public override bool CanConvert(Type objectType)
        {
            return (objectType == typeof(Teaser));
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            JObject jo = JObject.Load(reader);
            switch (jo["type"].Value<string>())
            {
                case "video":
                    return JsonConvert.DeserializeObject<Video>(jo.ToString(), SpecifiedSubclassConversion);
                case "brand":
                    return JsonConvert.DeserializeObject<Brand>(jo.ToString(), SpecifiedSubclassConversion);
                default:
                    throw new Exception();
            }
            throw new NotImplementedException();
        }

        public override bool CanWrite
        {
            get { return false; }
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            throw new NotImplementedException(); // won't be called because CanWrite returns false
        }
    }

Feel free to create custom logic in switch case hard code class name might not good idea instead create enum or something like but this is how you can achieve this type of scenario  

