I have a class with an interface-typed property like:
public class Foo
{
public IBar Bar { get; set; }
}
I also have multiple concrete implementations of the IBar
interface that can be set at runtime. Some of these concrete classes require a custom JsonConverter for serialization & deserialization.
Utilizing the TypeNameHandling.Auto
option the non-convertor requiring IBar
classes can be serialized and deserialized perfectly. The custom-serialized classes on the other hand have no $type
name output and while they are serialized as expected, they cannot be deserialized to their concrete type.
I attempted to write-out the $type
name metadata myself within the custom JsonConverter
; however, on deserialization the converter is then being bypassed entirely.
Is there a workaround or proper way of handling such a situation?
Best Answer
I solved the similar problem and I found a solution. It's not very elegant and I think there should be a better way, but at least it works. So my idea was to have
JsonConverter
per each type that implementsIBar
and one converter forIBar
itself.So let's start from models:
Now let's create converter for
IBar
. It will be used only when deserializing JSON. It will try to read$type
variable and call converter for implementing type:And this is converter for
BarA
class:You may notice that it's inherited from
BarBaseJsonConverter
class, notJsonConverter
. And also we do not useserializer
parameter inWriteJson
andReadJson
methods. There is a problem with usingserializer
parameter inside custom converters. You can read more here. We need to create new instance ofJsonSerializer
and base class is a good candidate for that:JsonHelper
is just a class to createJsonSerializerSettings
:Now it will work and you still can use your custom converters for both serialization and deserialization: