Serialize with known types
using System;
using JsonKnownTypes;
using Newtonsoft.Json;
namespace Test
{
[JsonConverter(typeof(JsonKnownTypesConverter<BaseClass>))]
public class BaseClass
{
public string Name {get;set;}
}
public class ChildClass:BaseClass
{
public string Detailed {get;set;}
}
public class MyClass
{
public ChildClass ChildClass {get;set;}
}
public class Program
{
public static void Main()
{
var myClass = new MyClass()
{
ChildClass = new ChildClass()
};
Console.WriteLine(JsonConvert.SerializeObject(myClass));
// output: {"ChildClass":{"$type":"ChildClass","Detailed":null,"Name":null}}
// but I think the $type should not be output, because the type is known.
JsonConvert.DeserializeObject<MyClass>("{\"ChildClass\":{\"$type\":\"ChildClass\",\"Detailed\":null,\"Name\":null}}");
// work
JsonConvert.DeserializeObject<MyClass>("{\"ChildClass\":{\"Detailed\":null,\"Name\":null}}");
// doesn't work
// it should work, because the type is known.
}
}
}
When I serialize MyClass, I think the $type of ChildClass should not be output, because the type is known. Vice versa, when I deserialize MyClass, I do not need to provide the $type.
You can refer https://dotnetfiddle.net/Mk0rkO for detail.
@KarlGong Hi, sorry for not replying for a long time. Use UseBaseTypeForCanConvert in JsonKnownTypesSettingsManager.DefaultDiscriminatorSettings or JsonDiscriminatorAttribute. Ive added the flag because i don't want to change current behaviour but your point is good. Thanks for help. Will release it soon
Dmitry, I am unable to get this scenario to work using the latest version available through Github.
On further reading, I found that Newtonsoft does not call CanConvert when the Converter is directly specified. Do you think this is reasonable to work around?
https://stackoverflow.com/a/26018381
A repro:
[TestClass]
public class KnownTypesDeserializeAsBaseErrorRepro
{
public enum ThingType
{
Base,
Derived,
}
[JsonConverter(typeof(JsonKnownTypesConverter<Base>))]
[JsonKnownTypeFallback(typeof(Base))]
[JsonDiscriminator(Name = nameof(Base.Type))]
public abstract class Base
{
public string BaseProp { get; set; }
public abstract ThingType Type { get; }
}
public class Derived : Base
{
public string DerivedProp { get; set; }
public override ThingType Type => ThingType.Derived;
}
[TestMethod]
public void TestDerivedTypeDeserialization()
{
//in the scenario where an endpoint accepts a derived type, and the client sends to type discriminator,
//everything should succeed
JsonKnownTypesSettingsManager.DefaultDiscriminatorSettings = new JsonDiscriminatorSettings { UseBaseTypeForCanConvert = false };
var @base = new Derived() { BaseProp = "base" };
var json = JsonConvert.SerializeObject(@base, Formatting.Indented);
Console.WriteLine(json);
//remove the $type discriminator to simulate the scenario
var token = JToken.Parse(json);
token["Type"].Parent.Remove();
Console.WriteLine(token.ToString(Formatting.Indented));
var deserialized = JsonConvert.DeserializeObject<Derived>(token.ToString());
}
}