1

I use .NET to cast the JSON string into a Dictionary via the System.Web.Script.Serialization.JavaScriptSerializer type in the 3.5 System.Web.Extensions assembly.

I keep JSON data in a dictionary object, looks like:

        // Simple POST request
        using (System.Net.WebClient wb = new System.Net.WebClient())
        {
            // Random user data API - http://randomuser.me/
            string url = "http://api.randomuser.me/";

            var data = new System.Collections.Specialized.NameValueCollection();
            var responseStringJson = Encoding.Default.GetString(wb.UploadValues(url, "POST", data));

            var jsSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();
            Dictionary<string, object> Results = jsSerializer.Deserialize<dynamic>(responseStringJson);
        }

JSON Data Example

{
  results: [{
    user: {
      gender: "male",
      name: {
        title: "mr",
        first: "patrick",
        last: "coleman"
      },
      location: {
        city: "stockton",
        state: "minnesota",
        zip: "10532"
      },
      email: "patrick.coleman45@example.com",
      username: "ticklishostrich48",
      password: "darkknight55",
      salt: ">DyBf9aih",
      md5: "5d6bf4508070fba41e2d602c847cdbd9",
      sha1: "19e5b0b59e6c86dbf370c431a7edb2aa4f1420a6",
      sha256: "9434e04d307839d9b6411254007072412c11f7e6b5d8fd848e56fe5f0c660a04"
    },
    version: "0.4"
  }]
}

How can I access data by key value? I would do something like:

Results["results"]["version"]
Results["results"]["user"]["name"]["first"]

Thanks in advance, Best regards, Christian.

LeMoussel
  • 5,290
  • 12
  • 69
  • 122

3 Answers3

2

Your original approach will work, if you modify it a little bit:

// Simple POST request
using (System.Net.WebClient wb = new System.Net.WebClient())
{
    // Random user data API - http://randomuser.me/
    string url = "http://api.randomuser.me/";

    var data = new System.Collections.Specialized.NameValueCollection();
    var responseStringJson = Encoding.Default.GetString(wb.UploadValues(url, "POST", data));

    var jsSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();
    var results = jsSerializer.Deserialize<dynamic>(responseStringJson);

    // Note that the following works, because Console.WriteLine
    // automatically formats those objects to a string. If you want
    // to use these anywhere else, you will have to cast/convert the
    // values every time you access them.
    Console.WriteLine(results["results"][0]["version"]);
    Console.WriteLine(results["results"][0]["user"]["name"]["first"]);
    Console.ReadLine();
}

I would, however, suggest that you create some strongly typed classes which you then use in your project. For example, if you put your API url into http://json2csharp.com/ and add those classes to your project, the code for reading the data would look a bit different:

// Simple POST request
using (System.Net.WebClient wb = new System.Net.WebClient())
{
    // Random user data API - http://randomuser.me/
    string url = "http://api.randomuser.me/";

    var data = new System.Collections.Specialized.NameValueCollection();
    var responseStringJson = Encoding.Default.GetString(wb.UploadValues(url, "POST", data));

    var jsSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();
    var results = jsSerializer.Deserialize<RootObject>(responseStringJson);

    Console.WriteLine(results.results[0].version);
    Console.WriteLine(results.results[0].user.name.first);
    Console.ReadLine();
}

The big advantages are that you can add type conversion to the proxy classes, without having to do that every time you access a value from the dictionary, and that you get full IDE and compiler support for the objects' properties (less typos):

hangy
  • 10,765
  • 6
  • 43
  • 63
0

If the value of each key is a dictionary too, then you must specify that in the declaration. Not sure if the deserializer you're using supports it but give it a try.

Dictionary<string, Dictionary<string, object>>

I wouldn't advice trying retrieve a full object immediately though, this might work for a single nested dictionary, but there are probably complexity limits. Its best to iterate over each KeyValuePair in the dictionary, if the value is a dictionary type, then cast is as such and handle it individually. This way the deserializer doesn't have to assume that all values are a dictionary by definition.

Leopold Asperger
  • 925
  • 1
  • 6
  • 12
0

How can I access data by key value? I would do something like:
Results["results"]["user"]["name"]["first"]

This syntax is not possible in C#, since variables are strongly typed. Actually, as hangy explained, this is possible with the new dynamic keyword in .net 4.0, which you already used in your question. According to this related answer, all you need to do is use System.Web.Helpers.Json.Decode() to deserialize your Json object, it will return a dynamic object, that you should be able to access somewhat like this: Results.results.user.name.first


Without the use of net 4.0 dynamic casting, you could also write a function like this:

 Results.GetValue("results","user","name","first");

You can write this method as an extension method for Dictionary:

public static class JsonNestedDictionaryExtensions
{
    public static Object GetValue(this Dictionary<String,Object> dict, params string[] keys)
    {
        Object dictObject = dict;
        String lastKey = "";
        foreach (string key in keys)
        {
             if (!dictObject is Dictionary<String,Object>)
                 throw new ArgumentException(key+ " cannot be accessed because "+lastKey+" is not a dictionary");
             dict = (Dictionary<String,Object>) dictObject;

             dictObject = dict["key"];
             lastKey = key;
        }

        return dictObject;
    }
}
Community
  • 1
  • 1
HugoRune
  • 13,157
  • 7
  • 69
  • 144
  • It does work if they just use the object as `dynamic` instead of casting it to `Dictionary`. But it's not really a nice way to work with that data. ;) – hangy Jul 05 '14 at 09:23
  • Thanks, I totally forgot about that new feature. – HugoRune Jul 05 '14 at 09:37