Casting interfaces for deserialization in JSON.NET Casting interfaces for deserialization in JSON.NET json json

Casting interfaces for deserialization in JSON.NET


@SamualDavis provided a great solution in a related question, which I'll summarize here.

If you have to deserialize a JSON stream into a concrete class that has interface properties, you can include the concrete classes as parameters to a constructor for the class! The NewtonSoft deserializer is smart enough to figure out that it needs to use those concrete classes to deserialize the properties.

Here is an example:

public class Visit : IVisit{    /// <summary>    /// This constructor is required for the JSON deserializer to be able    /// to identify concrete classes to use when deserializing the interface properties.    /// </summary>    public Visit(MyLocation location, Guest guest)    {        Location = location;        Guest = guest;    }    public long VisitId { get; set; }    public ILocation Location { get;  set; }    public DateTime VisitDate { get; set; }    public IGuest Guest { get; set; }}


Why use a converter? There is a native functionality in Newtonsoft.Json to solve this exact problem:

Set TypeNameHandling in the JsonSerializerSettings to TypeNameHandling.Auto

JsonConvert.SerializeObject(  toSerialize,  new JsonSerializerSettings()  {    TypeNameHandling = TypeNameHandling.Auto  });

This will put every type into the json, that is not held as a concrete instance of a type but as an interface or an abstract class.

Make sure that you are using the same settings for serialization and deserialization.

I tested it, and it works like a charm, even with lists.

Search ResultsWeb result with site links

⚠️ WARNING:

Only use this for json from a known and trusted source. User snipsnipsnip correctly mentioned that this is indeed a vunerability.

See CA2328 and SCS0028 for more information.


Source and an alternative manual implementation: Code Inside Blog


(Copied from this question)

In cases where I have not had control over the incoming JSON (and so cannot ensure that it includes a $type property) I have written a custom converter that just allows you to explicitly specify the concrete type:

public class Model{    [JsonConverter(typeof(ConcreteTypeConverter<Something>))]    public ISomething TheThing { get; set; }}

This just uses the default serializer implementation from Json.Net whilst explicitly specifying the concrete type.

An overview are available on this blog post. Source code is below:

public class ConcreteTypeConverter<TConcrete> : JsonConverter{    public override bool CanConvert(Type objectType)    {        //assume we can convert to anything for now        return true;    }    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)    {        //explicitly specify the concrete type we want to create        return serializer.Deserialize<TConcrete>(reader);    }    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)    {        //use the default serialization - it works fine        serializer.Serialize(writer, value);    }}