4
votes

I have the following JSON format delivered by a third party:

{
"data": {
    "objects": {
        "0ea73fa9333a7cbeb2d8c69a14b9970f": {
            "Id": "0ea73fa9333a7cbeb2d8c69a14b9970f",
            "Name": "test"
        },
        "38b1390ff6bc8a9837105d181000bcc8": {
            "Id": "38b1390ff6bc8a9837105d181000bcc8",
            "Name": "test"
        }
    }
}}

which i'm deserializing using this model:

public class ObjectTypes
{
    public ObjectTypeList data { get; set; }

    public class ObjectTypeList
    {
        public Dictionary<string, Object> objects { get; set; }
    }

    public class Object
    {
        public string Id { get; set; }
        public string Name { get; set; }
    }
}

This works fine, however sometimes the JSON is empty like this:

{
"data": {
    "objects": []
}
}

Which results in this exception:

Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'System.Collections.Generic.Dictionary`2[System.String,Models.ObjectTypes+Object]' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly. To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array. Path 'data.objects', line 1, position 20.

Any suggestions on how to resolve this?

2
@JeroenMink, your objects is not an array [] its object {} so here Dictionary<string, Object> doesn't work here - er-sho
@jeroen.mink do you have a sample json string that you cannot deserialize, i.e. throws an exception? - Rui Jarimba
I'd strongly recommend not naming a class Object. - spender
@RuiJarimba the last json (where the 'objects' property is empty is the one i can't deserialize - Jeroen Mink

2 Answers

0
votes

You shoul deserialize on the type ObjectTypes

        public partial class ObjectTypes
        {
            [JsonProperty("data")]
            public Data Data { get; set; }
        }

        public partial class Data
        {
            [JsonProperty("objects")]
            public Dictionary<string, Object> Objects { get; set; }
        }

        public partial class Object
        {
            [JsonProperty("Id")]
            public string Id { get; set; }

            [JsonProperty("Name")]
            public string Name { get; set; }
        }
0
votes

As I already mentioned in my comment, json structure doesn't match in both strings. objects can be either an object (Dictionary) or an array.

I have created a small parser class that will parse the json and check if objects is an object (Dictionary) or an array. In the first case it will return an empty ObjectTypes object but in the second case it will deserialize the json string into an ObjectTypes object.

public class ObjectTypesParser
{
    public ObjectTypes Parse(string json)
    {
        JToken token = JToken.Parse(json);
        var objectsToken = token.First.First.First.FirstOrDefault();

        if (objectsToken is JArray)
        {
            /*
             Special case - json with an empty array:

            {
                ""data"": {
                    ""objects"": []
                }
            }

            */
            return new ObjectTypes();
        }

        // json containing a dictionary:
        ObjectTypes data = JsonConvert.DeserializeObject<ObjectTypes>(json);

        return data;
    }
}

C# classes:

public class ObjectTypes
{
    [JsonProperty("data")]
    public ObjectTypeList Data { get; set; }

    public ObjectTypes()
    {
        Data = new ObjectTypeList();
    }
}

public class ObjectTypeList
{
    [JsonProperty("objects")]
    public Dictionary<string, ObjectData> Objects { get; set; }

    public ObjectTypeList()
    {
        Objects = new Dictionary<string, ObjectData>();
    }
}

public class ObjectData
{
    [JsonProperty("Id")]
    public string Id { get; set; }

    [JsonProperty("Name")]
    public string Name { get; set; }
}

Using the code:

string json1 = @"{
""data"": {
    ""objects"": {
        ""0ea73fa9333a7cbeb2d8c69a14b9970f"": {
            ""Id"": ""0ea73fa9333a7cbeb2d8c69a14b9970f"",
            ""Name"": ""test""
        },
        ""38b1390ff6bc8a9837105d181000bcc8"": {
            ""Id"": ""38b1390ff6bc8a9837105d181000bcc8"",
            ""Name"": ""test""
        }
    }
}}";

string json2 = @"{
""data"": {
    ""objects"": []
}
}";


var parser = new ObjectTypesParser();
ObjectTypes data1 = parser.Parse(json1);
ObjectTypes data2 = parser.Parse(json2);