I have 2 classes like this
class A: Base
{
public string CommonField;
public int IntField;
}
class B: Base
{
public string CommonField;
public double DoubleField;
}
I serialize A
instance with type name handling
{
"$type": "MyApp.A, MyApp",
"CommonField": "SomeValue",
"IntField": 123,
"SomeBaseField": 321
}
What would be the easiest way to get B
instance from this? Before you ask why, it's about importing A
as B
(they have base properties and those what names are matching as you see, so this operation is reasonable).
Trying to deserialize given json as B
will throw
Newtonsoft.Json.JsonSerializationException: Type specified in JSON 'MyApp.A, MyApp, Version=0.0.1.1, Culture=neutral, PublicKeyToken=null' is not compatible with 'MyApp.B, MyApp, Version=0.0.1.1, Culture=neutral, PublicKeyToken=null'. Path '$type', line 2, position 42.
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ResolveTypeName(JsonReader reader, Type& objectType, JsonContract& contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, String qualifiedTypeName)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ReadMetadataProperties(JsonReader reader, Type& objectType, JsonContract& contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue, Object& newValue, String& id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
I could think of following:
A
, create instance of B
and copy all values (bad);$type
in json and try to deserialize it as B
(better, still bad);SerializationBinder
and deserialize json as B
(good):public class JsonABBinder : DefaultSerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
if (typeName == "MyApp.A")
return typeof(B);
return base.BindToType(assemblyName, typeName);
}
}
Is there better way? In my scenario there are many such types and having hundereds of such binders (as well as reading json first as A
to determine which binder to apply) is very tedious.
I am looking for a simple way to ignore $type
and specify wanted type directly (generic method), because I know type I need, but I don't know which type is in json and I want to ignore it.
You can use:
new JsonSerializer().TypeNameHandling = TypeNameHandling.None
This will ignore $type.
It would be a good idea to pass in some settings when deseralizing the type:
private readonly JsonSerializerSettings _settings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.None
};
Then use it like:
var json = JsonConvert.DeserializeObject<object>(jsonString, _settings);
Or even simpler
var json = JsonConvert.DeserializeObject<object>(jsonString, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.None
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With