I have a bunch of custom JsonConverter
s where some are in charge of serialiation, and some of deserialization. I add them to a JsonSerializer
using the Converters
property.
My problem is that if I have one JsonConverter
for serializing a specific type, and another for deserializing the same type, the correct JsonConverter
is not chosen for the specific task, it is always the first one in the list of Converters
, where CanConvert returns true, that is chosen, regardless of whether that JsonConverter
CanWrite
or not.
In the below example, both CustomConverterA
and CustomConverterB
CanHandle the string
type, but only CustomConverterB
can write (the only difference is that CanWrite
returns true for CustomConverterB
). I would expect CustomConverterB
to be chosen.
But CustomConverterA
is chosen, however its WriteJson
method is never called. CustomConverterB
is skipped entirely since CustomConverterA
was chosen before it.
public class CustomConverterA : JsonConverter
{
public override bool CanWrite
{
get
{
Console.WriteLine("Inside CustomConverterA.CanWrite (returns false)");
return false;
}
}
public override bool CanRead => true;
public override bool CanConvert(Type objectType)
{
Console.WriteLine("Inside CustomConverterA.CanConvert");
if (objectType == typeof(string))
{
Console.WriteLine("return true");
return true;
}
Console.WriteLine("return false");
return false;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
Console.WriteLine("Inside CustomConverterA.WriteJson");
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
Console.WriteLine("Inside CustomConverterA.ReadJson");
return new object();
}
}
public class CustomConverterB : JsonConverter
{
public override bool CanWrite
{
get
{
Console.WriteLine("Inside CustomConverterB.CanWrite (returns true)");
return true;
}
}
public override bool CanRead => true;
public override bool CanConvert(Type objectType)
{
Console.WriteLine("Inside CustomConverterB.CanConvert");
if (objectType == typeof(string))
{
Console.WriteLine("return true");
return true;
}
Console.WriteLine("return false");
return false;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
Console.WriteLine("Inside CustomConverterB.WriteJson");
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
Console.WriteLine("Inside CustomConverterB.ReadJson");
return new object();
}
}
public void TestCustomConverter()
{
var serializer = new JsonSerializer()
{
Converters = {
new CustomConverterA(),
new CustomConverterB()
}
};
var data = "testdata";
using (var writer = new StringWriter())
{
serializer.Serialize(writer, data);
var serialized = writer.ToString();
Console.WriteLine("Serialized: " + serialized);
}
}
The above example outputs:
Inside CustomConverterA.CanConvert
return true
Inside CustomConverterA.CanWrite (returns false)
Serialized: "testdata"
Are JsonConverter
s supposed to work like this? Am I not supposed to be able to have different classes handle serialization and deserialization? If not, what is the purpose of the CanWrite
and CanRead
properties?