<PackageReference Include="NJsonSchema" Version="9.1.9" />

JsonInheritanceConverter

using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Linq; using System.Reflection; namespace NJsonSchema.Converters { public class JsonInheritanceConverter : JsonConverter { internal static readonly string DefaultDiscriminatorName = "discriminator"; private readonly string _discriminator; [ThreadStatic] private static bool _isReading; [ThreadStatic] private static bool _isWriting; public override bool CanWrite { get { if (_isWriting) { _isWriting = false; return false; } return true; } } public override bool CanRead { get { if (_isReading) { _isReading = false; return false; } return true; } } public JsonInheritanceConverter() { _discriminator = DefaultDiscriminatorName; } public JsonInheritanceConverter(string discriminator) { _discriminator = discriminator; } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { try { _isWriting = true; JObject jObject = JObject.FromObject(value, serializer); jObject.AddFirst(new JProperty(_discriminator, value.GetType().get_Name())); writer.WriteToken(jObject.CreateReader()); } finally { _isWriting = false; } } public override bool CanConvert(Type objectType) { return true; } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { JObject jObject = serializer.Deserialize<JObject>(reader); string discriminator = jObject.GetValue(_discriminator).Value<string>(); Type objectSubtype = GetObjectSubtype(objectType, discriminator); try { _isReading = true; return serializer.Deserialize(jObject.CreateReader(), objectSubtype); } finally { _isReading = false; } } private Type GetObjectSubtype(Type objectType, string discriminator) { dynamic val = (from a in objectType.GetTypeInfo().GetCustomAttributes() where a.GetType().get_Name() == "KnownTypeAttribute" select a).SingleOrDefault((Attribute a) => IsKnownTypeTargetType(a, discriminator)); if (val != null) return (Type)val.Type; string name = objectType.Namespace + "." + discriminator; return objectType.GetTypeInfo().get_Assembly().GetType(name); } private bool IsKnownTypeTargetType(dynamic attribute, string discriminator) { return (byte)(attribute?.Type.Name == discriminator) != 0; } } }