3

I need to implement remote connectivity for an existing reporting interface, which requires serialisation and de-serialisation of the data classes. Here is a simplified version of the classes and interfaces:

    public interface IBase
    {
        string Name { get; }
    }

    public interface IDerived1
    {
        int Value { get; }
    }

    public interface IDerived2
    {
        bool Value { get; }
    }

    public class Base : IBase
    {
        public string Name { get; protected set; }
    }

    public class Derived1 : Base, IDerived1
    {
        public int Value { get; protected set; }
    }

    public class Derived2 : Base, IDerived2
    {
        public bool Value { get; protected set; }
    }

As a input parameter I get

IEnumerable<IBase> reportingData

So this collection may contain any number and combination of instances of 'Derived1' and 'Derived2'. I then serialise the collection like this:

string serialisedReportingData = JsonConvert.SerializeObject( reportingData );

Which gives me for example this:

[{"Value":11,"Name":"Product Number"},{"Value":false,"Name":"Output 1 Enabled"}]

Obviously with this data alone, de-serialisation is impossible, as the type of the individual collection entries is not in the JSON. I could for example make the type part of the JSON or provide an additional collection of types for use during de-serialisation.

I have used CustomCreationConverter overloads before to deal with

JsonConvert.DeserializeObject<IEnumerable<Ixxx>>( ... );

type of scenarios, but this only applied to a single interface type inside the IEnumerable. In my example above I have two: IDerived1 and IDerived2.

My questions / issues:

a) I am not sure how a CustomCreationConverter could be written that deals with more than one interface type and I don't know how to get the type into this.

b) I would love your suggestions on how to implement a solution that would give me the same de-serialisation output as the 'IEnumerable reportingData' I received as input.

I would much appreciate a working code example, where possible.

Many thanks in advance, Christian

Christian
  • 33
  • 1
  • 3
  • 2
    If you don't want to include `"$type"` information, see [How to implement custom JsonConverter in JSON.NET to deserialize a List of base class objects?](https://stackoverflow.com/q/8030538) and [Deserializing polymorphic json classes without type information using json.net](https://stackoverflow.com/q/19307752). – dbc Sep 05 '17 at 18:28

1 Answers1

4

Update: (inspired by the comment from dbc)

You should use a SerializationBinder when deserializing with type names. See here for the KnownTypesBinder. (Newtonsoft.Json Version greater 10 is needed)

First, if you want to set your properties you have to make them public. Then you can use a JsonSerializerSettings to Serialize/Deserialize.

List<IBase> loList = new List<IBase>();
loList.Add(new Base() { Name = "Base" });
loList.Add(new Derived1() { Name = "Derived1", Value = 3 });
loList.Add(new Derived2() { Name = "Derived2", Value = true });

KnownTypesBinder loKnownTypesBinder = new KnownTypesBinder()
{
    KnownTypes = new List<Type> { typeof(Base), typeof(Derived1), typeof(Derived2) }
};

IEnumerable<IBase> reportingData = loList.AsEnumerable();
JsonSerializerSettings loJsonSerializerSettings = new JsonSerializerSettings()
{
    TypeNameHandling = TypeNameHandling.Objects,
    SerializationBinder = loKnownTypesBinder
};

string lsOut = JsonConvert.SerializeObject(reportingData, loJsonSerializerSettings);
reportingData = JsonConvert.DeserializeObject<IEnumerable<IBase>>(lsOut, loJsonSerializerSettings);

If you use the JsonSerializerSettingslike that, the type information will be include in the json string.

[{
        "$type": "Base",
        "Name": "Base"
    }, {
        "$type": "Derived1",
        "Value": 3,
        "Name": "Derived1"
    }, {
        "$type": "Derived2",
        "Value": true,
        "Name": "Derived2"
    }
]
PinBack
  • 2,114
  • 9
  • 15
  • `$type` information should be sanitized for security. See [TypeNameHandling caution in Newtonsoft Json](https://stackoverflow.com/q/39565954) for details. – dbc Sep 05 '17 at 18:29
  • Thank you SOOOO much! I did not expect the answer to be that straight forward. Not only I but also a few of my colleagues will appreciate your wisdom very much! :-) – Christian Sep 06 '17 at 08:56