1
{
"Profile": {
    "dProperty1": {
        "a": "value",
        "b": "value",
        "c": "value",
        "d": "value",
        "e": "value"
    },
    "dProperty2": {
        "a": "value",
        "b": "value",
        "d": "value",
        "e": "value"
    },
    "dProperty3": {
        "a": "value",
        "b": "value",
        "d": "value",
        "e": "value"
       }
    }
}

I have a JSON object, which can have any number of dynamic properties. All the properties are objects that consist of mostly of the same fields. How can i parse this JSON into a strongly typed object in C#?

Kristian Nissen
  • 1,153
  • 2
  • 11
  • 29
  • 1
    will they always stay the same name? It's a bit "unclean" but in the past I've created a class with all possible properties for the different variations, yet the JSON may not have all of them. It simply ignores the properties in the class that have no counterpart in the JSON. – Jeremy Dec 10 '15 at 13:04
  • 1
    Create type with all possible properties and deserealize JSON to it. – Alex Dec 10 '15 at 13:05
  • 1
    You can deserialize Profile as Dictionary (where AbcdeClass contains superposition of properties from JSON) like for example here http://stackoverflow.com/questions/20727787/deserialize-json-string-to-dictionarystring-object – Igor Popov Dec 10 '15 at 13:09

2 Answers2

3

If you must have strongly typed result I would deserialize Profile as a dictionary of superposition of properties

class AbscdeClass
{
    public string A { get; set; }
    public string B { get; set; }
    public string C { get; set; }
    public string D { get; set; }
    public string E { get; set; }
}

class JsonBody
{
    public Dictionary<string, AbscdeClass> Profile { get; set; }
}

and parse original JSON text as

JsonBody json = JsonConvert.DeserializeObject<JsonBody>(jsonString);
Igor Popov
  • 2,084
  • 16
  • 18
  • You say if i "must". Do you recommend another way? – Kristian Nissen Dec 10 '15 at 14:31
  • You can use dynamic types (as in answer from @Jon Skeet). In case of your example I would go for dictionary with static types. If superposition class becomes too big and structureless or if the list of properties can evolve rapidly I would do dynamics. Since you explicitly stated that you need static types this reasoning was unnecessary – Igor Popov Dec 10 '15 at 14:52
  • @Igor: I'm not using dynamic types. I'm parsing to a `JObject`, but I'm not using dynmamic typing anywhere, and I've still got a dictionary with a static type as the value too... Not that there's anything wrong with your approach either, mind you. – Jon Skeet Dec 10 '15 at 17:26
  • @Jon Skeet. My bad - I reacted too quick on JObject presence. The example of dynamic use of JObject.Parse can be found at http://stackoverflow.com/a/9326146/2413030 – Igor Popov Dec 10 '15 at 18:03
2

I would parse the whole tree as a JObject, and then call ToObject<> on appropriate sub-objects. Sample code:

using System;
using System.IO;
using System.Linq;
using Newtonsoft.Json.Linq;

class Example
{
    public string Name { get; set; }
    public int Age { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        var json = File.ReadAllText("test.json");
        var root = JObject.Parse(json);        
        var profile = (JObject) root["Profile"];
        var map = profile.Properties()
                         .ToDictionary(p => p.Name, p => p.Value.ToObject<Example>());
        foreach (var entry in map)
        {
            Console.WriteLine($"Key: {entry.Key}; Name: {entry.Value.Name}; Age: {entry.Value.Age}");
        }
    }
}

JSON:

{
  "Profile": {
    "dProperty1": {
      "name": "First",
      "age": 30,
      "extra": "Ignored"
    },
    "dProperty2": {
      "name": "Second",
      "age": 25
    },
    "dProperty3": {
      "name": "Third",
      "age": 50
    }
  }
}

Result:

Key: dProperty1; Name: First; Age: 30
Key: dProperty2; Name: Second; Age: 25
Key: dProperty3; Name: Third; Age: 50
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194