How to deserialize an object's property with a specific derived class

Viewed 183

I need Asp.net to deserialize an object's property with a specific derived class.

According to Newtonsoft's documentation, I should be able to change the JsonContract for the base class Equipment.Shared.Model.SimCard. https://www.newtonsoft.com/json/help/html/ContractResolver.htm

Class Transmitter has a property (Simcard) Equipment.Shared.Model.SimCard, but I need to have it deserialized as TlsModel.SimCard, otherwise TlsModel.SimCard properties are discarded during deserialization.

public class TlsModelContractResolver : DefaultContractResolver
{
    protected override JsonContract CreateContract(Type objectType)
    {
        JsonContract contract = base.CreateContract(objectType);

        if (objectType == typeof(Equipment.Shared.Model.SimCard) )
        {
            contract.CreatedType = typeof(SimCard);
            Console.WriteLine("Simcard CreateType is updated");

        }

        return contract;
    }
}

At the first deserialization, I have the log line 'Simcard CreateType is updated', so my contract deseralizer is taken into account.

But transmitter.SimCard is still a Equipment.Shared.Model.SimCard and not TlsModel.SimCard as I excptected.

Did I miss something ?

2 Answers

You must also replace the value of JsonContract.DefaultCreator with an appropriate creation function, and possibly set JsonContract.DefaultCreatorNonPublic = false if the base class did not have a public constructor:

public class TlsModelContractResolver : DefaultContractResolver
{
    protected override JsonContract CreateContract(Type objectType)
    {
        JsonContract contract = base.CreateContract(objectType);

        if (objectType == typeof(Equipment.Shared.Model.SimCard) )
        {
            contract.CreatedType = typeof(SimCard);
            Debug.WriteLine("Simcard CreateType is updated");
            contract.DefaultCreator = () => new SimCard();
            contract.DefaultCreatorNonPublic = false;
        }

        return contract;
    }
}

Notes:

Demo fiddle here.

If you are using newtonsoft json you can do it by using (at serialization and deserialization type) the Type Name Handling as explained here: https://www.newtonsoft.com/json/help/html/SerializeTypeNameHandling.htm

It just adds the property "@type" to each object.

Example

Consider the following class:

//dll My.Dll
namespace My.Namespace
public class MyObj {
    public string Name {get;set;}
    public object Whatever {get;set;}
}

var objInner = new MyObj { Name = "Inner" };
var objOuter = new MyObj { Name = "Outer", Whatever = obj1 }

var jsonString = JsonConvert.SerializeObject(objOuter, Formatting.Indented, new 
JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.All
});
Console.Writeline(jsonString);

//produces
//{
//  "@type": "My.Namespace.MyObj, My.Dll",
//  "Name":  "Outer",
//  "Whatever": {
//       "@type": "My.Namespace.MyObj, My.Dll",
//       "Name": "Inner"
//   }
//}

//to deserialize
var deserializedObj = JsonConvert.DserializeObject<MyObj>(objOuter, new 
JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.All
});
Related