简体   繁体   中英

Using Json.NET to deserialize this kind of data

I'm writing something for Omegle, and this is the kind of response I get:

{ "clientID" : "shard2:jgv1dnwhyffmld7kir5drlcwp7k6eu",
  "events" : [ [ "waiting" ],
      [ "statusInfo",
        { "antinudepercent" : 1.0,
          "antinudeservers" : [ "waw1.omegle.com",
              "waw2.omegle.com",
              "waw3.omegle.com"
            ],
          "count" : 28477,
          "servers" : [ "front1.omegle.com",
              "front8.omegle.com",
              "front7.omegle.com",
              "front9.omegle.com",
              "front2.omegle.com",
              "front5.omegle.com",
              "front3.omegle.com",
              "front6.omegle.com",
              "front4.omegle.com"
            ],
          "spyQueueTime" : 0.000099992752075199996,
          "spyeeQueueTime" : 0.8086000442504,
          "timestamp" : 1375197484.3550739
        }
      ]
    ]
}

To put this data into a dictionary, I've tried using the following function:

    private Dictionary<string, object> deserializeToDictionary(string jo)
    {
        Dictionary<string, object> values = JsonConvert.DeserializeObject<Dictionary<string, object>>(jo);
        Dictionary<string, object> values2 = new Dictionary<string, object>();
        foreach (KeyValuePair<string, object> d in values)
        {
            if (d.Value.GetType().FullName.Contains("Newtonsoft.Json.Linq.JObject"))
            {
                values2.Add(d.Key, deserializeToDictionary(d.Value.ToString()));
            }
            else
            {
                values2.Add(d.Key, d.Value);
            }

        }
        return values2;
    }

However, I get the following error:

Cannot deserialize the current JSON array (eg [1,2,3]) into type 'System.Collections.Generic.Dictionary2[System.String,System.Object]' because the type requires a JSON object (eg {"name":"value"}) to deserialize correctly.

To fix this error either change the JSON to a JSON object (eg {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (eg 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.

What am I doing wrong?

The short answer to your question, "why am I getting this error" is that your JSON is a mix of JSON objects and arrays, yet your code appears to be trying to deserialize everything into dictionaries. Json.Net can't deserialize an array into a dictionary, so it throws this error. When deserializing, you have to make sure to match JSON objects to .NET objects (or Dictionaries) and JSON arrays to .NET arrays (or Lists).

So, how do we get things working? Well, if you just want a generic function that can handle any arbitrary JSON and convert it into regular .NET types (primitives, Lists and Dictionaries), then you can use JSON.Net's Linq-to-JSON API to do something like this:

private static object Deserialize(string json)
{
    return ToObject(JToken.Parse(json));
}

private static object ToObject(JToken token)
{
    if (token.Type == JTokenType.Object)
    {
        Dictionary<string, object> dict = new Dictionary<string, object>();
        foreach (JProperty prop in ((JObject)token).Properties())
        {
            dict.Add(prop.Name, ToObject(prop.Value));
        }
        return dict;
    }
    else if (token.Type == JTokenType.Array)
    {
        List<object> list = new List<object>();
        foreach (JToken value in token.Values())
        {
            list.Add(ToObject(value));
        }
        return list;
    }
    else
    {
        return ((JValue)token).Value;
    }
}

On the other hand, why go to all that trouble, when you can just keep everything as JObjects and JArrays and use the API to go directly after what you're looking for? For example, if you want to get all the event names you can do this:

var events = JObject.Parse(json)["events"];
var eventNames = events.Select(a => a[0].Value<string>()).ToList();

If you wanted to get all the messages for all "gotMessage" events you could do:

var messages = events.Where(a => a[0].Value<string>() == "gotMessage")
                     .Select(a => a[1].Value<string>())
                     .ToList();

Discalimer: I am not at all familiar with "Omegle" or its API, so I am just guessing at what the format of the JSON is based on your question and comments. I also don't know exactly what data you're interested in, so you'll almost certainly need to make adjustments to suit your needs. Hopefully these examples are enough to get you "unstuck". I would also suggest checking out the Linq-to-JSON samples in the documentation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM