I have an object with a list of base class sub-objects. Sub-objects need a custom converter. I can’t make my custom converter respect ItemTypeNameHandling option.
Sample code (create a new C# Console project, add JSON.NET NuGet package):
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
namespace My {
class Program {
private static void Main () {
Console.WriteLine(JsonConvert.SerializeObject(
new Box { toys = { new Spintop(), new Ball() } },
Formatting.Indented));
Console.ReadKey();
}
}
[JsonObject] class Box
{
[JsonProperty (
ItemConverterType = typeof(ToyConverter),
ItemTypeNameHandling = TypeNameHandling.Auto)]
public List<Toy> toys = new List<Toy>();
}
[JsonObject] class Toy {}
[JsonObject] class Spintop : Toy {}
[JsonObject] class Ball : Toy {}
class ToyConverter : JsonConverter {
public override void WriteJson (JsonWriter writer, object value, JsonSerializer serializer) {
serializer.Serialize(writer, value);
}
public override object ReadJson (JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
return serializer.Deserialize(reader, objectType);
}
public override bool CanConvert (Type objectType) {
return typeof(Toy).IsAssignableFrom(objectType);
}
}
}
Produced output:
{
"toys": [
{},
{}
]
}
Necessary output (this is what happens if I comment ItemConverterType = typeof(ToyConverter), line):
{
"toys": [
{
"$type": "My.Spintop, Serialization"
},
{
"$type": "My.Ball, Serialization"
}
]
}
I’ve tried temporarily changing value of serializer.TypeNameHandling in ToyConverter.WriteJson method, but it affects unrelated properties. (Of course, my real converter is more complex than that. It’s just an example with base functionality.)
Question: How to make my custom JsonConverter respect ItemTypeNameHandling property of JsonProperty attribute?
Having delved into the source code for Json.Net (version 4.5 release 11), it looks as though what you want to do is not possible.
The key to getting types written to the output is this method:
It’s the
containerContractandcontainerPropertyparameters that are important here. When serializing without a converter, these parameters are supplied andShouldWriteTypeis able to use them to figure out whatTypeNameHandlingto use.When serializing with a converter, however, those two parameters are not supplied. This appears to be because
ToyConverter.WriteJsonresults in a call toNewtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValuelike this:Note that the last two parameters are in fact a
JsonContainerContract containerContractandJsonProperty containerProperty, and are passed down the chain to theShouldWriteTypemethod. Therein lies the problem: because they are null, the logic of theShouldWriteTypemethod means that it returnsfalse, thus the type is not written.Edit:
Inspired by this, you could workaround this problem by customising the
WriteJsonmethod of your converter:Note that that
RemoveAssemblyDetailsmethod is ripped straight from the Json.Net source.You will of course need to modify the
WriteJsonmethod to output the rest of the fields, but hopefully that does the trick.