if the $type property is used to support polymorphic properties, it will fail to work if it does not proceed other properties for the type. The exception given is "Could not create an instance of type Ixxxxxx. Type is an interface or abstract class and cannot be instantiated."
Linqpad script that demonstrates:
void Main()
{
var settings = new JsonSerializerSettings();
settings.TypeNameHandling = TypeNameHandling.All;
string magicTypeString = typeof(Parent).FullName.Replace("Parent","{0}") + ", " + typeof(Parent).Assembly.GetName();
magicTypeString.Dump();
settings.Binder = new TypeNameSerializationBinder(magicTypeString);
settings.NullValueHandling = NullValueHandling.Ignore;
////// when $type isnt first in list of other properties, fails....
var jsonWorks = @"
{
""Child"": {
""$type"": ""Foo"",
""SomeProperty"": ""RandomValue""
}
}
";
var jsonFails = @"
{
""Child"": {
""SomeProperty"": ""RandomValue"",
""$type"": ""Foo""
}
}
";
JsonConvert.DeserializeObject<Parent>( jsonWorks, settings ).Dump("Works");
JsonConvert.DeserializeObject<Parent>( jsonFails, settings ).Dump("Fails"); // this will throw an exception
}
public class Parent
{
public ISomeInterface Child { get; set; }
}
public interface ISomeInterface
{
}
public class Foo : ISomeInterface
{
public string SomeProperty { get; set; }
}
public class Bar : ISomeInterface
{
public string SomeProperty { get; set; }
}
public class TypeNameSerializationBinder : SerializationBinder
{
public string TypeFormat { get; private set; }
public TypeNameSerializationBinder(string typeFormat)
{
TypeFormat = typeFormat;
}
public override void BindToName(Type serializedType, out string assemblyName, out string typeName)
{
assemblyName = null;
typeName = serializedType.Name;
}
public override Type BindToType(string assemblyName, string typeName)
{
string resolvedTypeName = string.Format(TypeFormat, typeName);
return Type.GetType(resolvedTypeName, true);
}
}