Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
I am trying to extend the JSON.net example given here
http://james.newtonking.com/projects/json/help/CustomCreationConverter.html
I have another sub class deriving from base class/Interface
public class Person
public string FirstName { get; set; }
public string LastName { get; set; }
public class Employee : Person
public string Department { get; set; }
public string JobTitle { get; set; }
public class Artist : Person
public string Skill { get; set; }
List<Person> people = new List<Person>
new Employee(),
new Employee(),
new Artist(),
How do I deserialize following Json back to List< Person >
"Department": "Department1",
"JobTitle": "JobTitle1",
"FirstName": "FirstName1",
"LastName": "LastName1"
"Department": "Department2",
"JobTitle": "JobTitle2",
"FirstName": "FirstName2",
"LastName": "LastName2"
"Skill": "Painter",
"FirstName": "FirstName3",
"LastName": "LastName3"
I don't want to use TypeNameHandling JsonSerializerSettings. I am specifically looking for custom JsonConverter implementation to handle this. The documentation and examples around this are pretty sparse on the net. I can't seem to get the the overridden ReadJson() method implementation in JsonConverter right.
Using the standard CustomCreationConverter
, I was struggling to work how to generate the correct type (Person
or Employee
), because in order to determine this you need to analyse the JSON and there is no built in way to do this using the Create
method.
I found a discussion thread pertaining to type conversion and it turned out to provide the answer. Here is a link: Type converting (archived link).
What's required is to subclass JsonConverter
, overriding the ReadJson
method and creating a new abstract Create
method which accepts a JObject
.
The JObject class provides a means to load a JSON object and
provides access to the data within this object.
The overridden ReadJson
method creates a JObject
and invokes the Create
method (implemented by our derived converter class), passing in the JObject
instance.
This JObject
instance can then be analysed to determine the correct type by checking existence of certain fields.
Example
string json = "[{
\"Department\": \"Department1\",
\"JobTitle\": \"JobTitle1\",
\"FirstName\": \"FirstName1\",
\"LastName\": \"LastName1\"
\"Department\": \"Department2\",
\"JobTitle\": \"JobTitle2\",
\"FirstName\": \"FirstName2\",
\"LastName\": \"LastName2\"
{\"Skill\": \"Painter\",
\"FirstName\": \"FirstName3\",
\"LastName\": \"LastName3\"
List<Person> persons =
JsonConvert.DeserializeObject<List<Person>>(json, new PersonConverter());
public class PersonConverter : JsonCreationConverter<Person>
protected override Person Create(Type objectType, JObject jObject)
if (FieldExists("Skill", jObject))
return new Artist();
else if (FieldExists("Department", jObject))
return new Employee();
return new Person();
private bool FieldExists(string fieldName, JObject jObject)
return jObject[fieldName] != null;
public abstract class JsonCreationConverter<T> : JsonConverter
/// <summary>
/// Create an instance of objectType, based properties in the JSON object
/// </summary>
/// <param name="objectType">type of object expected</param>
/// <param name="jObject">
/// contents of JSON object that will be deserialized
/// </param>
/// <returns></returns>
protected abstract T Create(Type objectType, JObject jObject);
public override bool CanConvert(Type objectType)
return typeof(T).IsAssignableFrom(objectType);
public override bool CanWrite
get { return false; }
public override object ReadJson(JsonReader reader,
Type objectType,
object existingValue,
JsonSerializer serializer)
// Load JObject from stream
JObject jObject = JObject.Load(reader);
// Create target object based on JObject
T target = Create(objectType, jObject);
// Populate the object properties
serializer.Populate(jObject.CreateReader(), target);
return target;
–
–
–
–
–
The above solution for the JsonCreationConverter<T>
is all over the internet, but has a flaw that manifests itself in rare occasions. The new JsonReader created in the ReadJson method does not inherit any of the original reader's configuration values (Culture, DateParseHandling, DateTimeZoneHandling, FloatParseHandling, etc...). These values should be copied over before using the new JsonReader in serializer.Populate().
This is the best I could come up with to fix some of the problems with the above implementation, but I still think there are some things being overlooked:
Update I updated this to have a more explicit method that makes a copy of an existing reader. This just encapsulates the process of copying over individual JsonReader settings. Ideally this function would be maintained in the Newtonsoft library itself, but for now, you can use the following:
/// <summary>Creates a new reader for the specified jObject by copying the settings
/// from an existing reader.</summary>
/// <param name="reader">The reader whose settings should be copied.</param>
/// <param name="jToken">The jToken to create a new reader for.</param>
/// <returns>The new disposable reader.</returns>
public static JsonReader CopyReaderForObject(JsonReader reader, JToken jToken)
JsonReader jTokenReader = jToken.CreateReader();
jTokenReader.Culture = reader.Culture;
jTokenReader.DateFormatString = reader.DateFormatString;
jTokenReader.DateParseHandling = reader.DateParseHandling;
jTokenReader.DateTimeZoneHandling = reader.DateTimeZoneHandling;
jTokenReader.FloatParseHandling = reader.FloatParseHandling;
jTokenReader.MaxDepth = reader.MaxDepth;
jTokenReader.SupportMultipleContent = reader.SupportMultipleContent;
return jTokenReader;
This should be used as follows:
public override object ReadJson(JsonReader reader,
Type objectType,
object existingValue,
JsonSerializer serializer)
if (reader.TokenType == JsonToken.Null)
return null;
// Load JObject from stream
JObject jObject = JObject.Load(reader);
// Create target object based on JObject
T target = Create(objectType, jObject);
// Populate the object properties
using (JsonReader jObjectReader = CopyReaderForObject(reader, jObject))
serializer.Populate(jObjectReader, target);
return target;
Older solution follows:
/// <summary>Base Generic JSON Converter that can help quickly define converters for specific types by automatically
/// generating the CanConvert, ReadJson, and WriteJson methods, requiring the implementer only to define a strongly typed Create method.</summary>
public abstract class JsonCreationConverter<T> : JsonConverter
/// <summary>Create an instance of objectType, based properties in the JSON object</summary>
/// <param name="objectType">type of object expected</param>
/// <param name="jObject">contents of JSON object that will be deserialized</param>
protected abstract T Create(Type objectType, JObject jObject);
/// <summary>Determines if this converted is designed to deserialization to objects of the specified type.</summary>
/// <param name="objectType">The target type for deserialization.</param>
/// <returns>True if the type is supported.</returns>
public override bool CanConvert(Type objectType)
// FrameWork 4.5
// return typeof(T).GetTypeInfo().IsAssignableFrom(objectType.GetTypeInfo());
// Otherwise
return typeof(T).IsAssignableFrom(objectType);
/// <summary>Parses the json to the specified type.</summary>
/// <param name="reader">Newtonsoft.Json.JsonReader</param>
/// <param name="objectType">Target type.</param>
/// <param name="existingValue">Ignored</param>
/// <param name="serializer">Newtonsoft.Json.JsonSerializer to use.</param>
/// <returns>Deserialized Object</returns>
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
if (reader.TokenType == JsonToken.Null)
return null;
// Load JObject from stream
JObject jObject = JObject.Load(reader);
// Create target object based on JObject
T target = Create(objectType, jObject);
//Create a new reader for this jObject, and set all properties to match the original reader.
JsonReader jObjectReader = jObject.CreateReader();
jObjectReader.Culture = reader.Culture;
jObjectReader.DateParseHandling = reader.DateParseHandling;
jObjectReader.DateTimeZoneHandling = reader.DateTimeZoneHandling;
jObjectReader.FloatParseHandling = reader.FloatParseHandling;
// Populate the object properties
serializer.Populate(jObjectReader, target);
return target;
/// <summary>Serializes to the specified type</summary>
/// <param name="writer">Newtonsoft.Json.JsonWriter</param>
/// <param name="value">Object to serialize.</param>
/// <param name="serializer">Newtonsoft.Json.JsonSerializer to use.</param>
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
serializer.Serialize(writer, value);
–
–
Just thought i would share a solution also based on this that works with the Knowntype attribute using reflection , had to get derived class from any base class, solution can benefit from recursion to find the best matching class though i didn't need it in my case, matching is done by the type given to the converter if it has KnownTypes it will scan them all until it matches a type that has all the properties inside the json string, first one to match will be chosen.
usage is as simple as:
string json = "{ Name:\"Something\", LastName:\"Otherthing\" }";
var ret = JsonConvert.DeserializeObject<A>(json, new KnownTypeConverter());
in the above case ret will be of type B.
JSON classes:
[KnownType(typeof(B))]
public class A
public string Name { get; set; }
public class B : A
public string LastName { get; set; }
Converter code:
/// <summary>
/// Use KnownType Attribute to match a divierd class based on the class given to the serilaizer
/// Selected class will be the first class to match all properties in the json object.
/// </summary>
public class KnownTypeConverter : JsonConverter
public override bool CanConvert(Type objectType)
return System.Attribute.GetCustomAttributes(objectType).Any(v => v is KnownTypeAttribute);
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
// Load JObject from stream
JObject jObject = JObject.Load(reader);
// Create target object based on JObject
System.Attribute[] attrs = System.Attribute.GetCustomAttributes(objectType); // Reflection.
// Displaying output.
foreach (System.Attribute attr in attrs)
if (attr is KnownTypeAttribute)
KnownTypeAttribute k = (KnownTypeAttribute) attr;
var props = k.Type.GetProperties();
bool found = true;
foreach (var f in jObject)
if (!props.Any(z => z.Name == f.Key))
found = false;
break;
if (found)
var target = Activator.CreateInstance(k.Type);
serializer.Populate(jObject.CreateReader(),target);
return target;
throw new ObjectNotFoundException();
// Populate the object properties
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
throw new NotImplementedException();
–
The project JsonSubTypes implement a generic converter that handle this feature with the helps of attributes.
For the concrete sample provided here is how it works:
[JsonConverter(typeof(JsonSubtypes))]
[JsonSubtypes.KnownSubTypeWithProperty(typeof(Employee), "JobTitle")]
[JsonSubtypes.KnownSubTypeWithProperty(typeof(Artist), "Skill")]
public class Person
public string FirstName { get; set; }
public string LastName { get; set; }
public class Employee : Person
public string Department { get; set; }
public string JobTitle { get; set; }
public class Artist : Person
public string Skill { get; set; }
[TestMethod]
public void Demo()
string json = "[{\"Department\":\"Department1\",\"JobTitle\":\"JobTitle1\",\"FirstName\":\"FirstName1\",\"LastName\":\"LastName1\"}," +
"{\"Department\":\"Department1\",\"JobTitle\":\"JobTitle1\",\"FirstName\":\"FirstName1\",\"LastName\":\"LastName1\"}," +
"{\"Skill\":\"Painter\",\"FirstName\":\"FirstName1\",\"LastName\":\"LastName1\"}]";
var persons = JsonConvert.DeserializeObject<IReadOnlyCollection<Person>>(json);
Assert.AreEqual("Painter", (persons.Last() as Artist)?.Skill);
This is an expansion to totem's answer. It does basically the same thing but the property matching is based on the serialized json object, not reflect the .net object. This is important if you're using [JsonProperty], using the CamelCasePropertyNamesContractResolver, or doing anything else that will cause the json to not match the .net object.
Usage is simple:
[KnownType(typeof(B))]
public class A
public string Name { get; set; }
public class B : A
public string LastName { get; set; }
Converter code:
/// <summary>
/// Use KnownType Attribute to match a divierd class based on the class given to the serilaizer
/// Selected class will be the first class to match all properties in the json object.
/// </summary>
public class KnownTypeConverter : JsonConverter {
public override bool CanConvert( Type objectType ) {
return System.Attribute.GetCustomAttributes( objectType ).Any( v => v is KnownTypeAttribute );
public override bool CanWrite {
get { return false; }
public override object ReadJson( JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer ) {
// Load JObject from stream
JObject jObject = JObject.Load( reader );
// Create target object based on JObject
System.Attribute[ ] attrs = System.Attribute.GetCustomAttributes( objectType ); // Reflection.
// check known types for a match.
foreach( var attr in attrs.OfType<KnownTypeAttribute>( ) ) {
object target = Activator.CreateInstance( attr.Type );
JObject jTest;
using( var writer = new StringWriter( ) ) {
using( var jsonWriter = new JsonTextWriter( writer ) ) {
serializer.Serialize( jsonWriter, target );
string json = writer.ToString( );
jTest = JObject.Parse( json );
var jO = this.GetKeys( jObject ).Select( k => k.Key ).ToList( );
var jT = this.GetKeys( jTest ).Select( k => k.Key ).ToList( );
if( jO.Count == jT.Count && jO.Intersect( jT ).Count( ) == jO.Count ) {
serializer.Populate( jObject.CreateReader( ), target );
return target;
throw new SerializationException( string.Format( "Could not convert base class {0}", objectType ) );
public override void WriteJson( JsonWriter writer, object value, JsonSerializer serializer ) {
throw new NotImplementedException( );
private IEnumerable<KeyValuePair<string, JToken>> GetKeys( JObject obj ) {
var list = new List<KeyValuePair<string, JToken>>( );
foreach( var t in obj ) {
list.Add( t );
return list;
As another variation on Totem's known type solution, you can use reflection to create a generic type resolver to avoid the need to use known type attributes.
This uses a technique similar to Juval Lowy's GenericResolver for WCF.
As long as your base class is abstract or an interface, the known types will be automatically determined rather than having to be decorated with known type attributes.
In my own case I opted to use a $type property to designate type in my json object rather than try to determine it from the properties, though you could borrow from other solutions here to use property based determination.
public class JsonKnownTypeConverter : JsonConverter
public IEnumerable<Type> KnownTypes { get; set; }
public JsonKnownTypeConverter() : this(ReflectTypes())
public JsonKnownTypeConverter(IEnumerable<Type> knownTypes)
KnownTypes = knownTypes;
protected object Create(Type objectType, JObject jObject)
if (jObject["$type"] != null)
string typeName = jObject["$type"].ToString();
return Activator.CreateInstance(KnownTypes.First(x => typeName == x.Name));
return Activator.CreateInstance(objectType);
throw new InvalidOperationException("No supported type");
public override bool CanConvert(Type objectType)
if (KnownTypes == null)
return false;
return (objectType.IsInterface || objectType.IsAbstract) && KnownTypes.Any(objectType.IsAssignableFrom);
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
// Load JObject from stream
JObject jObject = JObject.Load(reader);
// Create target object based on JObject
var target = Create(objectType, jObject);
// Populate the object properties
serializer.Populate(jObject.CreateReader(), target);
return target;
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
throw new NotImplementedException();
//Static helpers
static Assembly CallingAssembly = Assembly.GetCallingAssembly();
static Type[] ReflectTypes()
List<Type> types = new List<Type>();
var referencedAssemblies = Assembly.GetExecutingAssembly().GetReferencedAssemblies();
foreach (var assemblyName in referencedAssemblies)
Assembly assembly = Assembly.Load(assemblyName);
Type[] typesInReferencedAssembly = GetTypes(assembly);
types.AddRange(typesInReferencedAssembly);
return types.ToArray();
static Type[] GetTypes(Assembly assembly, bool publicOnly = true)
Type[] allTypes = assembly.GetTypes();
List<Type> types = new List<Type>();
foreach (Type type in allTypes)
if (type.IsEnum == false &&
type.IsInterface == false &&
type.IsGenericTypeDefinition == false)
if (publicOnly == true && type.IsPublic == false)
if (type.IsNested == false)
continue;
if (type.IsNestedPrivate == true)
continue;
types.Add(type);
return types.ToArray();
It can then be installed as a formatter
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new JsonKnownTypeConverter());
A lot of the times the implementation will exist in the same namespace as the interface. So, I came up with this:
public class InterfaceConverter : JsonConverter
public override bool CanWrite => false;
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
var token = JToken.ReadFrom(reader);
var typeVariable = this.GetTypeVariable(token);
if (TypeExtensions.TryParse(typeVariable, out var implimentation))
else if (!typeof(IEnumerable).IsAssignableFrom(objectType))
implimentation = this.GetImplimentedType(objectType);
var genericArgumentTypes = objectType.GetGenericArguments();
var innerType = genericArgumentTypes.FirstOrDefault();
if (innerType == null)
implimentation = typeof(IEnumerable);
Type genericType = null;
if (token.HasAny())
var firstItem = token[0];
var genericTypeVariable = this.GetTypeVariable(firstItem);
TypeExtensions.TryParse(genericTypeVariable, out genericType);
genericType = genericType ?? this.GetImplimentedType(innerType);
implimentation = typeof(IEnumerable<>);
implimentation = implimentation.MakeGenericType(genericType);
return JsonConvert.DeserializeObject(token.ToString(), implimentation);
public override bool CanConvert(Type objectType)
return !typeof(IEnumerable).IsAssignableFrom(objectType) && objectType.IsInterface || typeof(IEnumerable).IsAssignableFrom(objectType) && objectType.GetGenericArguments().Any(t => t.IsInterface);
protected Type GetImplimentedType(Type interfaceType)
if (!interfaceType.IsInterface)
return interfaceType;
var implimentationQualifiedName = interfaceType.AssemblyQualifiedName?.Replace(interfaceType.Name, interfaceType.Name.Substring(1));
return implimentationQualifiedName == null ? interfaceType : Type.GetType(implimentationQualifiedName) ?? interfaceType;
protected string GetTypeVariable(JToken token)
if (!token.HasAny())
return null;
return token.Type != JTokenType.Object ? null : token.Value<string>("$type");
Therefore, you can include this globally like so:
public static JsonSerializerSettings StandardSerializerSettings => new JsonSerializerSettings
Converters = new List<JsonConverter>
new InterfaceConverter()
Using the idea of totem and zlangner, I have created a KnownTypeConverter
that will be able to determine the most appropriate inheritor, while taking into account that json data may not have optional elements.
So, the service sends a JSON response that contains an array of documents (incoming and outgoing). Documents have both a common set of elements and different ones.
In this case, the elements related to the outgoing documents are optional and may be absent.
In this regard, a base class Document
was created that includes a common set of properties.
Two inheritor classes are also created:
- OutgoingDocument
adds two optional elements "device_id"
and "msg_id"
;
- IncomingDocument
adds one mandatory element "sender_id"
;
The task was to create a converter that based on json data and information from KnownTypeAttribute will be able to determine the most appropriate class that allows you to save the largest amount of information received. It should also be taken into account that json data may not have optional elements.
To reduce the number of comparisons of json elements and properties of data models, I decided not to take into account the properties of the base class and to correlate with json elements only the properties of the inheritor classes.
Data from the service:
"documents": [
"document_id": "76b7be75-f4dc-44cd-90d2-0d1959922852",
"date": "2019-12-10 11:32:49",
"processed_date": "2019-12-10 11:32:49",
"sender_id": "9dedee17-e43a-47f1-910e-3a88ff6bc258",
"document_id": "5044a9ac-0314-4e9a-9e0c-817531120753",
"date": "2019-12-10 11:32:44",
"processed_date": "2019-12-10 11:32:44",
"total": 2
Data models:
/// <summary>
/// Service response model
/// </summary>
public class DocumentsRequestIdResponse
[JsonProperty("documents")]
public Document[] Documents { get; set; }
[JsonProperty("total")]
public int Total { get; set; }
// <summary>
/// Base document
/// </summary>
[JsonConverter(typeof(KnownTypeConverter))]
[KnownType(typeof(OutgoingDocument))]
[KnownType(typeof(IncomingDocument))]
public class Document
[JsonProperty("document_id")]
public Guid DocumentId { get; set; }
[JsonProperty("date")]
public DateTime Date { get; set; }
[JsonProperty("processed_date")]
public DateTime ProcessedDate { get; set; }
/// <summary>
/// Outgoing document
/// </summary>
public class OutgoingDocument : Document
// this property is optional and may not be present in the service's json response
[JsonProperty("device_id")]
public string DeviceId { get; set; }
// this property is optional and may not be present in the service's json response
[JsonProperty("msg_id")]
public string MsgId { get; set; }
/// <summary>
/// Incoming document
/// </summary>
public class IncomingDocument : Document
// this property is mandatory and is always populated by the service
[JsonProperty("sender_sys_id")]
public Guid SenderSysId { get; set; }
Converter:
public class KnownTypeConverter : JsonConverter
public override bool CanConvert(Type objectType)
return System.Attribute.GetCustomAttributes(objectType).Any(v => v is KnownTypeAttribute);
public override bool CanWrite => false;
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
// load the object
JObject jObject = JObject.Load(reader);
// take custom attributes on the type
Attribute[] attrs = Attribute.GetCustomAttributes(objectType);
Type mostSuitableType = null;
int countOfMaxMatchingProperties = -1;
// take the names of elements from json data
HashSet<string> jObjectKeys = GetKeys(jObject);
// take the properties of the parent class (in our case, from the Document class, which is specified in DocumentsRequestIdResponse)
HashSet<string> objectTypeProps = objectType.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Select(p => p.Name)
.ToHashSet();
// trying to find the right "KnownType"
foreach (var attr in attrs.OfType<KnownTypeAttribute>())
Type knownType = attr.Type;
if(!objectType.IsAssignableFrom(knownType))
continue;
// select properties of the inheritor, except properties from the parent class and properties with "ignore" attributes (in our case JsonIgnoreAttribute and XmlIgnoreAttribute)
var notIgnoreProps = knownType.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Where(p => !objectTypeProps.Contains(p.Name)
&& p.CustomAttributes.All(a => a.AttributeType != typeof(JsonIgnoreAttribute) && a.AttributeType != typeof(System.Xml.Serialization.XmlIgnoreAttribute)));
// get serializable property names
var jsonNameFields = notIgnoreProps.Select(prop =>
string jsonFieldName = null;
CustomAttributeData jsonPropertyAttribute = prop.CustomAttributes.FirstOrDefault(a => a.AttributeType == typeof(JsonPropertyAttribute));
if (jsonPropertyAttribute != null)
// take the name of the json element from the attribute constructor
CustomAttributeTypedArgument argument = jsonPropertyAttribute.ConstructorArguments.FirstOrDefault();
if(argument != null && argument.ArgumentType == typeof(string) && !string.IsNullOrEmpty((string)argument.Value))
jsonFieldName = (string)argument.Value;
// otherwise, take the name of the property
if (string.IsNullOrEmpty(jsonFieldName))
jsonFieldName = prop.Name;
return jsonFieldName;
HashSet<string> jKnownTypeKeys = new HashSet<string>(jsonNameFields);
// by intersecting the sets of names we determine the most suitable inheritor
int count = jObjectKeys.Intersect(jKnownTypeKeys).Count();
if (count == jKnownTypeKeys.Count)
mostSuitableType = knownType;
break;
if (count > countOfMaxMatchingProperties)
countOfMaxMatchingProperties = count;
mostSuitableType = knownType;
if (mostSuitableType != null)
object target = Activator.CreateInstance(mostSuitableType);
using (JsonReader jObjectReader = CopyReaderForObject(reader, jObject))
serializer.Populate(jObjectReader, target);
return target;
throw new SerializationException($"Could not serialize to KnownTypes and assign to base class {objectType} reference");
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
throw new NotImplementedException();
private HashSet<string> GetKeys(JObject obj)
return new HashSet<string>(((IEnumerable<KeyValuePair<string, JToken>>) obj).Select(k => k.Key));
public static JsonReader CopyReaderForObject(JsonReader reader, JObject jObject)
JsonReader jObjectReader = jObject.CreateReader();
jObjectReader.Culture = reader.Culture;
jObjectReader.DateFormatString = reader.DateFormatString;
jObjectReader.DateParseHandling = reader.DateParseHandling;
jObjectReader.DateTimeZoneHandling = reader.DateTimeZoneHandling;
jObjectReader.FloatParseHandling = reader.FloatParseHandling;
jObjectReader.MaxDepth = reader.MaxDepth;
jObjectReader.SupportMultipleContent = reader.SupportMultipleContent;
return jObjectReader;
PS: In my case, if no one inheritor has not been selected by converter (this can happen if the JSON data contains information only from the base class or the JSON data does not contain optional elements from the OutgoingDocument
), then an object of the OutgoingDocument
class will be created, since it is listed first in the list of KnownTypeAttribute
attributes. At your request, you can vary the implementation of the KnownTypeConverter
in this situation.
Here's another solution that avoids the use of jObject.CreateReader()
, and instead creates a new JsonTextReader
(which is the behavior used by the default JsonCreate.Deserialze
method:
public abstract class JsonCreationConverter<T> : JsonConverter
protected abstract T Create(Type objectType, JObject jObject);
public override bool CanConvert(Type objectType)
return typeof(T).IsAssignableFrom(objectType);
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
if (reader.TokenType == JsonToken.Null)
return null;
// Load JObject from stream
JObject jObject = JObject.Load(reader);
// Create target object based on JObject
T target = Create(objectType, jObject);
// Populate the object properties
StringWriter writer = new StringWriter();
serializer.Serialize(writer, jObject);
using (JsonTextReader newReader = new JsonTextReader(new StringReader(writer.ToString())))
newReader.Culture = reader.Culture;
newReader.DateParseHandling = reader.DateParseHandling;
newReader.DateTimeZoneHandling = reader.DateTimeZoneHandling;
newReader.FloatParseHandling = reader.FloatParseHandling;
serializer.Populate(newReader, target);
return target;
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
serializer.Serialize(writer, value);
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.