How to Map Nested JSON Objects to a .NET Dictionary

Sometimes a public JSON API responds in a format that you can’t control. For example, nested objects instead of an array:

{
   "companies": {
      "abc" : "Abc Company",
      "def" : "Def Company"
   }
}

And this list will grow with new property names each time you call the API:

{
   "companies": {
      "abc" : "Abc Company",
      "def" : "Def Company",
      "ghi" : "Ghi Company",
      "123abc" : "Some Other Name"
   }
}

If you’re like me, you’ve struggled to interpret JSON where property names and things are not known at compile time. In our case, since companies isn’t a JSON Array, how do you deserialize it to the .NET Collection type you need?

Exploratory Tests

With Newtonsoft Json.NET, we can solve a lot of problems like this. I’ll use my patented pseudo-REPL technique ;) When I’m writing tests for a legacy app, I find myself really wanting to look at the properties of objects without using the debugger.

Below, you’ll notice _output.WriteLine(data.ToJSON()) on line 14. I call it my test pseudo-REPL because I use it to evaluate some piece of code and examine the results with my test runner.

You can download my .ToJSON helper method from Nuget with:

Install-Package ToJSON

I find using this to build my tests is much faster than the debugger.

public class DeserializeJsonTests {
    private readonly ITestOutputHelper _output;

    public DeserializeJsonTests(ITestOutputHelper output) {
        _output = output;
    }

    [Fact]
    public void deserialize_to_dictionary_string_string() {

        string json = @"{'abc':'Abc Company','def':'Def Company','ghi':'Ghi Company'}";
        Dictionary data = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);

        _output.WriteLine(data.ToJSON());

        //http://www.newtonsoft.com/json/help/html/DeserializeDictionary.htm
        //{
        //  "abc": "Abc Company",
        //  "def": "Def Company",
        //  "ghi": "Ghi Company"
        //}
    }

Here, I took the nested objects out of the response… I cheated. I just wanted to show you how easy it would be if we received a JSON response we could work with.

We really need to drill down to the nested objects before we map them to a plain old .NET Collection.

LINQ to JSON

Json.NET’s LINQ to JSON is good for traversing your JSON to get it into the .NET data structure you need. In our case, we can use JObject and JProperty

Here’s how I would deserialize the JSON we started with:

[Fact]
public void deserialize_to_linq_to_json_jobject() {

    string json = @"{'companies': {'abc' : 'Abc Company', 'def' : 'Def Company', 'ghi' : 'Ghi Company' }}";

    JObject parent = JObject.Parse(json);
    var companies = parent.Value<JObject>("companies").Properties();

    //For illustration purposes
    foreach (var company in companies) {
        _output.WriteLine(company.Name + " : " + company.Value);
    }
    //abc : Abc Company
    //def : Def Company
    //ghi : Ghi Company

    var companiesDict = companies
        .ToDictionary(
            k => k.Name,
            v => v.Value.ToString());

    _output.WriteLine(companiesDict.GetType().ToString());
    //System.Collections.Generic.Dictionary`2[System.String,System.String]

    _output.WriteLine(companiesDict.ToJSON());
    //{
    //  "abc": "Abc Company",
    //  "def": "Def Company",
    //  "ghi": "Ghi Company"
    //}
}

On line 6, we parse the JSON string into a JObject, which allows us to query using LINQ to JSON. We then parse the companies JSON properties into IEnumerable<JProperty>

Finally, on line 17, we use LINQ’s .ToDictionary to map our IEnumerable<JProperty> to a Dictionary<string,string>

Summary

We were able to use Json.NET’s LINQ to JSON to wrangle some oddly-shaped JSON into a Dictionary. Hope you find this helpful someday!

Thanks for reading, and remember to sign up for my newsletter to make sure you get these tidbits delivered right to your inbox!



Tweet
comments powered by Disqus