3

I have a JSON data that looks like this:

{
    "Item1": {
        "Field1": "Val1",
        "Field2": "Val2"
    },
    "Item2": {
        "Field1": "Val11",
        "Field2": "Val22"
    },
    ....
    "ItemN": {
        "Field1": "Val1",
        "Field2": "Val2"
    },
}

I need to deserialize it to a set of classes that look like this:

public class Root
{
    public Item Item1;
    public Item Item2;

    public List<Item> Items; // << all the Items should go here
}

public class Item
{
    public string Field1;
    public string Field2;
}

How can I make Newtonsoft.Json to map data this way when deserializing?

user626528
  • 13,999
  • 30
  • 78
  • 146
  • Your json should be composed as an array in order for this to work. – Travis J Aug 16 '17 at 21:49
  • You can deserialize into a `Dictionary` as shown in [Deserializing JSON when key values are unknown](https://stackoverflow.com/a/24901245/3744182) or [Deserializing JSON with unknown object names](https://stackoverflow.com/q/38688570/3744182) or [Create a strongly typed c# object from json object with ID as the name](https://stackoverflow.com/a/34213724/3744182) or [Parsing JSON Object with variable properties into strongly typed object](https://stackoverflow.com/q/34202496/3744182). – dbc Aug 03 '20 at 19:48
  • In fact this could have been closed as a duplicate of those in 2017. Was a dictionary not acceptable? If you need to use a `List` then do you need to capture the `"ItemN"` names somewhere, or can they be discarded? – dbc Aug 03 '20 at 19:53

4 Answers4

11

No need for class Root. I would deserialize to a Dictionary

var dict= JsonConvert.DeserializeObject<Dictionary<string, Item>>(json);
L.B
  • 114,136
  • 19
  • 178
  • 224
  • can you please this a little? how would it map the JS array of objects to a Dictionary and what will the deserialization do here? – Zeeshan Adil Jun 25 '18 at 08:48
7

If you need to populate the Items list and the individual Item properties shown in your Root class from the same data in the JSON, then you will need a custom JsonConverter to do it. The following converter should work:

public class RootConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(Root);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject obj = JObject.Load(reader);
        var root = new Root();

        // populate all known Root properties 
        serializer.Populate(obj.CreateReader(), root);

        // populate Items list with all objects that can be converted to an Item
        root.Items = obj.Properties()
                        .Where(p => p.Value.Type == JTokenType.Object && 
                                    (p.Value["Field1"] != null || p.Value["Field2"] != null))
                        .Select(p => p.Value.ToObject<Item>())
                        .ToList();
        return root;
    }

    public override bool CanWrite
    {
        get { return false; }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

Then to use it, add a [JsonConverter] attribute to your Root class like this:

[JsonConverter(typeof(RootConverter))]
public class Root
{
    public Item Item1 { get; set; }
    public Item Item2 { get; set; }

    public List<Item> Items; // << all the Items should go here
}

Fiddle: https://dotnetfiddle.net/aADhzw

Brian Rogers
  • 125,747
  • 31
  • 299
  • 300
2

From @L.B post: If you need work with Root object you can try this way:

public class Root : Dictionary<string, Item>
{
    public List<Item> Items => this.Values.ToList();
}

Then you can deserialize JSON to Root object:

 var root = JsonConvert.DeserializeObject<Root>(json);
Dilshod K
  • 2,924
  • 1
  • 13
  • 46
-3

Use:

public class Root
{
    public List<Item> Items {get;set;}
}
public class Item
{
    public string Field1 {get;set;}
    public string Field2; {get;set;}
}

As the classes, and call:

Root foobar = new JavaScriptSerializer().Deserialize<Root>(result);

To deserialise.

0liveradam8
  • 752
  • 4
  • 18