1

I cannot figure out how to deserialize this JSON. The first nested object is always changing. This causes an error every time I try to run the code. I've stared at Newtonsofts Anonymous samples and just can't decipher how to use it here.

{
    "donations" : {
        "5859453c0a2c0b777ee6b686" : {
            "id" : "5859453c0a2c0b777ee6b686",
            "package" : {
                "_id" : {
                    "$oid" : "5833a3580a2c0b40ec7c9c9a"
                },
                "channel_perks" : [{
                        "viewer_points" : 10
                    }, {
                        "mysterybag" : 2
                    }
                ],
            },
            "updated_at" : "2016-12-20T14:50:36.996Z"
        },
        "585c18c60a2c0b02b189ac7a" : {
            "package" : {
                "_id" : {
                    "$oid" : "585988a50a2c0b777ee6bc0e"
                },
                "channel_perks" : [{
                        "viewer_points" : 10
                    }, {
                        "slap" : 2
                    }
                ],
            },
            "updated_at" : "2016-12-22T18:17:42.690Z"
        },
        "585e9e240a2c0b02b189b3e2" : {
            "id" : "585e9e240a2c0b02b189b3e2",
            "package" : {
                "_id" : {
                    "$oid" : "585988a50a2c0b777ee6bc11"
                },
                "channel_perks" : [{
                        "viewer_points" : 100
                    }, {
                        "slap" : 35
                    }, {
                        "mysterybag" : 30
                    }
                ],
            },
            "updated_at" : "2016-12-24T16:11:17.021Z"
        },
    },
}

I'm attempting to use Newtonsoft.Json but I'm open to other options. I've created these classes to read the code:

class APIResponse
{
    public DonationID donations { get; set; }
}
class DonationID
{
    public DonationJSON id { get; set; }
}
class DonationJSON
{
    public string id { get; set; }
    public PackageJSON package { get; set; }
    public string updated_at { get; set; }
}

class PackageJSON
{
    public PackageID _id { get; set; }
    public List<ChannelPerks> channel_perks { get; set; }
}
class PackageID
{
    [JsonProperty(PropertyName = "$oid")]
    public string oid { get; set; }
}
class ChannelPerks
{
    public string viewer_points { get; set; }
    public string mysterybag { get; set; }
    public string slap { get; set; }
}

Then I try to call it with this code:

    var definition = new APIResponse();
    var data = JsonConvert.DeserializeAnonymousType(JSONDATA, definition);

I've read many posts about JavaSerialize and Joption as well as JSON.net, but can't find any solution that works. Is this task impossible?

Stanton
  • 65
  • 1
  • 9
  • I doubt that you can deserialize property keys like "5859453c0a2c0b777ee6b686". Wouldn't it be better to serialize those objects as an array/list? – JeffRSon Mar 11 '17 at 10:57
  • I'm not serializing them to begin with. I'm pulling the JSON from a website API. – Stanton Mar 11 '17 at 11:04
  • Make your root object have a `public Dictionary donations { get; set; }` property. See [Create a strongly typed c# object from json object with ID as the name](https://stackoverflow.com/q/34213566/3744182) for a similar question. – dbc Mar 12 '17 at 01:15

2 Answers2

2

You could parse it using JObject (although you won't have strong typing) and use coalescence to extract values out of it. For example:

using (var stream = new FileStream(path, FileMode.Open))
{
    using (var reader = new StreamReader(stream))
    {
        string data = reader.ReadToEnd();
        var json = JObject.Parse(data);

        var donationId = json?["donations"]?["5859453c0a2c0b777ee6b686"]?["id"]?.ToString() ?? "";
    }
}

You could even build up your objects manually (albeit as a subset) if you desperately needed them to be typed :-)

gplumb
  • 712
  • 6
  • 29
  • I tried to use your sample code, but get a syntax error on the line: json["donations"]?["5859453c0a2c0b777ee6b686"]?["id"]?.ToString() ?? "" – Stanton Mar 11 '17 at 11:32
  • Ah, I typod! Try this: `var donationId = json?["donations"]?["5859453c0a2c0b777ee6b686"]?["id"]?.ToString() ?? "";` – gplumb Mar 11 '17 at 11:40
  • In thinking about this some more, if you don't know the ids of the objects ahead of time (which I'm guessing you won't), you'll have to walk over the nodes using .Children() - There's some LINQ examples here that will help too: http://www.newtonsoft.com/json/help/html/QueryingLINQtoJSON.htm – gplumb Mar 11 '17 at 11:44
1

After several hours of plugging away in the LINQ direction gplumb recommended. I've got a working deserialization script. Basically I had to use JOption to carve out the individual child objects, then manipulate the child strings to be usable, then deserialize into a class.
Lots of fun!

Here's the code:

    //Polling response from URL
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);
    HttpWebResponse response = (HttpWebResponse)request.GetResponse();
    StreamReader resStream = new StreamReader(response.GetResponseStream());

    //Parsing response to separate out each donation
    JObject ParsedJson = JObject.Parse(resStream.ReadToEnd());
    var TransactionArray = ParsedJson["donations"].Children();

    //Array to store parsed results into usable format
    List<DonationsJSON> TransArray = new List<DonationsJSON> { };
    foreach (object Transaction in TransactionArray)
    {
        // clean up parsed string and remove Anonymous ID string
        string DonationString = Transaction.ToString().Replace("\r\n", "");
        DonationString = DonationString.Substring(DonationString.IndexOf(':') + 1);

        // Deserializing string into Donation class and adding to List
        DonationsJSON TX = JsonConvert.DeserializeObject<DonationsJSON>(DonationString);
        TransArray.Add(TX);
    }
Stanton
  • 65
  • 1
  • 9