Rather than trying to deserialize as a Container<ContentX>
for concrete type(s) X
, you should deserialize as a Container<IContentType>
using a custom JsonConverter
that pre-load the JSON into a JToken
and infers the concrete type along the lines of How to implement custom JsonConverter in JSON.NET to deserialize a List of base class objects? or Deserializing polymorphic json classes without type information using json.net or Json.Net Serialization of Type with Polymorphic Child Object.
Thus your converter would look something like:
public class ContentConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(IContentType);
}
Type GetConcreteType(JObject obj)
{
if (obj.GetValue(nameof(ContentA.SomePropertyOfContentA), StringComparison.OrdinalIgnoreCase) != null)
return typeof(ContentA);
// Add other tests for other content types.
// Return a default type or throw an exception if a unique type cannot be found.
throw new JsonSerializationException("Cannot determine concrete type for IContentType");
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
var obj = JObject.Load(reader);
var concreteType = GetConcreteType(obj);
return obj.ToObject(concreteType, serializer);
}
public override bool CanWrite { get { return false; } }
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
And your call to JsonConvert
would look like:
var settings = new JsonSerializerSettings
{
Converters = { new ContentConverter() },
};
var model = JsonConvert.DeserializeObject<Container<IContentType>>(json, settings);
Finally, you might be able to choose the type entirely automatically using
new JsonDerivedTypeConverer<IContentType>(typeof(ContentA), typeof(ContentB), typeof(ContentC), typeof(ContentD))
Where JsonDerivedTypeConverer<T>
is taken from JsonConverter with Interface.