Just a quick post here but hopefully helpful if you hit the same issue. If you are dealing with json serialization, newtonsoft is one of our goto options.
When deserializing json to poco’s, sometimes the structure of your poco’s require a bit of extra setup to play fair with newtonsoft. Consider the following objects:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
class MyPoco { public string Name { get; set; } public ISubProperty SubProperty { get; set; } } interface ISubProperty { int Count { get; set; } } class SubProperty : ISubProperty { public int Count { get; set; } } |
So when this gets serialized, you’d end up with:
1 2 3 4 5 6 7 8 9 10 11 12 |
var myPoco = new MyPoco { Name="My poco name", SubProperty = new SubProperty { Count = 2 } }; string json = JsonConvert.SerializeObject(myPoco); ... {"Name":"My poco name","SubProperty":{"Count":2}} |
If you then try to deserialize:
1 |
MyPoco clone = JsonConvert.DeserializeObject<MyPoco>(json); |
then you will get an exception.
The solution is to setup a converter:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
internal class InterfaceConverter<TInterface, TImplementation> : JsonConverter where TImplementation : class { private static readonly string interfaceFullName = typeof(TInterface).FullName; public override bool CanConvert(Type objectType) { AssertTypes(); return objectType.FullName == interfaceFullName; } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { AssertTypes(); if (objectType.FullName == interfaceFullName) { return serializer.Deserialize(reader, typeof(TImplementation)); } throw new NotSupportedException($"Type {objectType} unexpected."); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { serializer.Serialize(writer, value); } private static void AssertTypes() { if (!typeof(TInterface).IsInterface) { throw new NotSupportedException($"TInterface must be an interface"); } if (!typeof(TInterface).IsAssignableFrom(typeof(TImplementation))) { throw new NotSupportedException($"typeof(TImplementation) ({typeof(TImplementation)}) must implement typeof(TInterface) ({typeof(TInterface)})"); } } } |
Which then gets passed into the deserialize call e.g.:
1 2 3 4 5 6 7 8 9 |
JsonSerializerSettings jsonSerializerSettings = new JsonSerializerSettings { Converters = new List<JsonConverter> { new InterfaceConverter<ISubProperty, SubProperty>() } }; MyPoco validClone = JsonConvert.DeserializeObject<MyPoco>(json, jsonSerializerSettings); |
Then you can simply add as many InterfaceConverter’s as you need