0

There are MANY questions and some very good answers about using Json.NET to deserialize to an interface instead of a concrete class. A quick search of Stack Overflow will turn up lots of related results. That said, I do not believe any of the questions specifically address the use case of an array of interfaces. So I do not believe this is a duplicate question - if I have missed a post, please link to it.

Given an interface like this:

public interface IFoo
{
    public string Bar { get; set; }
}

And 2 implementations like this:

public class Foo1 : IFoo
{
    public string Bar { get; set; }
    public bool Other1 { get; set; }
}

public class Foo2 : IFoo
{
    public string Bar { get; set; }
    public int Other2 { get; set; }
}

And finally a parent class:

public class Parent
{
    public IFoo[] Foos { get; set; }
}

I would expect that I should be able to deserialize a JSON payload like this:

{
    "Foos": [{
            "$type": "Foo1, MyLibrary",
            "Bar": "I am a Foo 1",
            "Other1": true
        }, {
            "$type": "Foo2, MyLibrary",
            "Bar": "I am a Foo 2",
            "Other2": 999
        }
    ]
}

using the following statement:

Parent parent = JsonConvert.DeserializeObject<Parent>(json, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto })

The result I am seeing is not an exception being thrown, but simply that parent.Foos is null.

What am I missing?

maxmoore14
  • 701
  • 7
  • 26
  • 2
    Can't reproduce, see https://dotnetfiddle.net/vGgAhM. Are you sure you have the correct values for `"$type"`? It should be `"FullTypeName, AssemblyName"` but `"$type": "Foo1, MyLibrary"` doesn't show a namespace at all for `Foo1` which would be very unusual. – dbc Nov 15 '22 at 04:01
  • This is very interesting to me - I think the fiddle will help for sure. You are correct that I accidentally left the namespaces off the sample code in the question, but I do have them in my code. But with the fiddle, I can attempt to compare side by side and see what I find. Thanks for the proof of concept. – maxmoore14 Nov 15 '22 at 10:50
  • Check to see whether your app has global default settings [`JsonConvert.DefaultSettings`](https://www.newtonsoft.com/json/help/html/p_newtonsoft_json_jsonconvert_defaultsettings.htm) set up somewhere. That might affect something, for instance by setting up a [`SerializationBinder`](https://www.newtonsoft.com/json/help/html/P_Newtonsoft_Json_JsonSerializerSettings_SerializationBinder.htm) which fails to correctly resolve Foo1 and Foo2. – dbc Nov 15 '22 at 15:34
  • I've been testing further based on your example and I think I am accidentally suppressing an exception on one of the subproperties. I am now getting an exception that 0.0 is not a valid integer. I know by default, it will deserialize "0" to int. Do I need a custom converter to handle numeric JSON values like 0.0 or 1.0 or 2.0 as int? – maxmoore14 Nov 15 '22 at 20:58
  • Yes, you would need a converter for that. An example would be the one from [this answer](https://stackoverflow.com/a/17749727) by Brian Rogers to [How can I restore the int deserialization behavior after upgrading Json.NET?](https://stackoverflow.com/q/17745866). You might want to improve it e.g. by checking that the floating value really was an integer. – dbc Nov 15 '22 at 21:05
  • Incidentally, the error handling feature in Json.NET is ["very flaky"](https://github.com/JamesNK/Newtonsoft.Json/issues/1580#issuecomment-358546723) according to [JamesNK](https://github.com/JamesNK), the author of the package. You might not want to depend on it too much. Actually, might [Regression from Json.NET v6: cannot skip an invalid object value type in an array via exception handling #1580](https://github.com/JamesNK/Newtonsoft.Json/issues/1580) be exactly what is happening to you? In that issue swallowing an exception for an array item caused the array to be null. – dbc Nov 15 '22 at 21:07
  • 1
    I think you nailed it spot on. That issue you linked to seems to be exactly what I am experiencing. You have been incredibly helpful. I will implement the custom converter and I expect that will resolve the issue. – maxmoore14 Nov 16 '22 at 02:02

0 Answers0