0

Hard to describe in words, but the API call I'm using returns JSON strings with integer names rather than something that can easily be converted to a class. You'll see in the example what I mean.

To start, I've examined the following Stackoverflow posts already, and they're helping but not giving me a complete solution to this particular JSON to C# class deserialization issue I'm having:

Nuts and bolts and why are the posts above not exactly helping?

Here's the JSON:

{    
    "related_objects": {
        "user": {
            "4243432": {
                "id": 4243432,
                "name": "Mary Poppins",
                "email": "mary@poppins.com",
                "has_pic": false,
                "pic_hash": null,
                "active_flag": false
            },
            "10658120": {
                "id": 10658120,
                "name": "Jack Spratt",
                "email": "jack@couldeatnofat.com",
                "has_pic": false,
                "pic_hash": null,
                "active_flag": true
            }
        },
        "person": {
            "425": {
                "id": 425,
                "name": "Jack L. Spratt",
                "email": [{
                        "label": "work",
                        "value": "jack@couldeatnofat.com",
                        "primary": true
                    }
                ],
                "phone": [{
                        "label": "work",
                        "value": "7045551212",
                        "primary": true
                    }
                ]
            }
        },
        "organization": {
            "96": {
                "id": 96,
                "name": "Leopards Domain",
                "people_count": 1,
                "owner_id": 4243432,
                "address": null,
                "cc_email": "spottedcat@kittens.com"
            },
            "220": {
                "id": 220,
                "name": "Gentle Giants",
                "people_count": 0,
                "owner_id": 10658120,
                "address": null,
                "cc_email": "wolf@hound.com"
            },
            "221": {
                "id": 221,
                "name": "Mice, Inc",
                "people_count": 0,
                "owner_id": 10658120,
                "address": null,
                "cc_email": "marvin@rodentsrus.com"
            },
            "222": {
                "id": 222,
                "name": "Footware",
                "people_count": 0,
                "owner_id": 10658120,
                "address": null,
                "cc_email": "jenny@socksandshoes.com"
            },
            "223": {
                "id": 223,
                "name": "Ignore Univ",
                "people_count": 1,
                "owner_id": 10658120,
                "address": null,
                "cc_email": "talktothehand@ignoreu.com"
            }
        }
    }
}

If I run this through my favorite JSON to C# converter site, I'll get something like this:

public class __invalid_type__4243432
{
    public int id { get; set; }
    public string name { get; set; }
    public string email { get; set; }
    public bool has_pic { get; set; }
    public object pic_hash { get; set; }
    public bool active_flag { get; set; }
}

Which, I would be tempted to use, if it weren't for the fact that this call is getting something for a specific user id. If I ask for the same information for another user id, I'll get different integer returns for the name attributes.

What have I done? Well, I've read the postings noted, and I'm able to do this:

public class UserProperties
{
    public int id { get; set; }
    public string name { get; set; }
    public string email { get; set; }
    public string has_pic { get; set; }
    public string pic_hash { get; set; }
    public string active_flag { get; set; }
}

And, as a test, use this constant string:

  public const string USERENTRIES =
        "{ " +
        "   \"4243432\": { " +
        "       \"id\": 4243432, " +
        "       \"name\": \"Mary Poppins\", " +
        "       \"email\": \"mary@poppins.com\", " +
        "       \"has_pic\": false, " +
        "       \"pic_hash\": null, " +
        "       \"active_flag\": false " +
        "   }, " +
        "   \"10658120\": { " +
        "       \"id\": 10658120, " +
        "       \"name\": \"O. Susanna\", " +
        "       \"email\": \"O@susanna.com\", " +
        "       \"has_pic\": false, " +
        "       \"pic_hash\": null, " +
        "       \"active_flag\": true " +
        "   } " +
        "}";

And convert it like this, successfully:

Dictionary<string, UserProperties> userentries = JsonConvert.DeserializeObject<Dictionary<string, UserProperties>>(USERENTRIES);

You're probably wondering what the problem is. well, it's the fact that this dictionary construct is actually the value for the name "user" in the user/value JSON pair, as noted:

"user": {
    "4243432": {
        "id": 4243432,
        "name": "Mary Poppins",
        "email": "mary@poppins.com",
        "has_pic": false,
        "pic_hash": null,
        "active_flag": false
    },
    "10658120": {
        "id": 10658120,
        "name": "Jack Spratt",
        "email": "jack@couldeatnofat.com",
        "has_pic": false,
        "pic_hash": null,
        "active_flag": true
    }
}

What I need, in C#, I think, is something like this:

[JsonObject(Description = "user")]
public class User
{
    public Dictionary<string, UserProperties> UserProperties { get; set; }
}

Which I would used to make the conversion like so:

var user = JsonConvert.DeserializeObject<User>(USER);

This returns null.

This is my test JSON constant:

public const string USER =
    "   { " +
    "       \"user\": { " +
    "            \"4243432\": { " +
    "                \"id\": 4243432, " +
    "                \"name\": \"Mary Poppins\", " +
    "                \"email\": \"mary@poppins.com\", " +
    "                \"has_pic\": false, " +
    "                \"pic_hash\": null, " +
    "                \"active_flag\": false " +
    "            }, " +
    "            \"10658120\": { " +
    "                \"id\": 10658120, " +
    "                \"name\": \"O. Susanna\", " +
    "                \"email\": \"O@Susanna.com\", " +
    "                \"has_pic\": false, " +
    "                \"pic_hash\": null, " +
    "                \"active_flag\": true " +
    "            } " +
    "        } " +
    "   }";

I've tried to provide everything here if anyone wants to try it out. Of course, I'm using Newtonsoft.

I feel like I'm missing just one thing. The difference between this scenario and the others in the other postings is that the odd name/value pairs are contained within another name. In the examples, the odd name/value pairs were either not contained within anything or were themselves containers of something else.

Seems to me that the deserialization of the odd name/value pair needs to be done in some way that is apart from the deserialization of the parent class.

If this needs a specific converter built, then I'd appreciate pointers to how to do that. Likewise, if an attribute set makes it easier, that too. I noted that in one posting, the responder suggesting specifying attributes. I'd appreciate any examples of using attributes to resolve this also.

Dan7el
  • 1,995
  • 5
  • 24
  • 46

1 Answers1

2

You're 99.99% there. Use the JsonProperty attribute to tell it that UserProperties is called user in the JSON, and JsonConvert.DeserializeObject<User>(USER) returns a valid User.

[JsonObject(Description = "user")]
public class User
{
    [JsonProperty(PropertyName = "user")]
    public Dictionary<string, UserProperties> UserPropererties { get; set; }
}

You could also just rename User.UserProperties to User.user, but I assume you'd rather have some control over the process.

You could make that Dictionary<int, UserProperties>, too. Works for me.