How to deserialize a dynamically named root node with json.NET

c#, deserialization, json.net

Solution

I would keep the first part of your solution (deserializing to `JObject`), but I wouldn't do another serialization. My code would look like this:

var jo = JObject.Parse(json);
var jp = jo.Properties().First();
var name = jp.Name;
var person = jp.Value.ToObject<Person>();

Edit:

In case you want a custom converter, you could use the following code. The converter converts your object to a list of `Person`s where every property represents another `Person`.

class PersonListConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var list = (PersonList) value;

        writer.WriteStartObject();

        foreach (var p in list.Persons)
        {
            writer.WritePropertyName(p.Name);
            serializer.Serialize(writer, p);
        }

        writer.WriteEndObject();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var jo = serializer.Deserialize<JObject>(reader);
        var result = new PersonList();
        result.Persons = new List<Person>();

        foreach (var prop in jo.Properties())
        {
            var p = prop.Value.ToObject<Person>();
            // set name from property name
            p.Name = prop.Name;
            result.Persons.Add(p);
        }

        return result;
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(PersonList);
    }
}

Where `PersonList` would look like this:

[JsonConverter(typeof(PersonListConverter))]
class PersonList
{
    public List<Person> Persons { get; set; }
}

Problem

This is an example of the json file: ``` {    "John Smith": {       "id": "72389",       "email": "johnsmith@gmail.com",       "books": [          {             "id": "0",             "title": "The Hunger Games",             "rating": "5"          },          {             "id": "1",             "title": "Harry Potter and the Order of the Phoenix",             "rating": "3"          },       ],       "magazines": [          {             "id": "2",             "title": "National Geographic",             "rating": "1"          },          {             "id": "3",             "title": "Wired",             "rating": "4"          }       ],    } } ``` Notice the root node has a dynamic name (John Smith), and every json I need to deserialize will have a different name. This json structure would require to have classes setup as follows: ``` public class RootObject { public JohnSmith { get; set; } } public class JohnSmith //oops { public string id { get; set; } public string email { get; set; } public List<Book> books { get; set; } public List<Magazine> magazines { get; set; } } public class Book { public string id { get; set; } public string title { get; set; } public string rating { get; set; } } public class Magazine { public string id { get; set; } public string title { get; set; } public string rating { get; set; } } ``` My goal is to deserialize "bypassing/ignoring" root object and most importantly that dynamicaly named node. This is not crucial, but I would like to be able to get the last name and set as a property on the Person class. ``` public class Person { public string id { get; set; } public string email { get; set; } public string name { get; set; } public List<Book> books { get; set; } public List<Magazine> magazines { get; set; } } public class Book { public string id { get; set; } public string title { get; set; } public string rating { get; set; } } public class Magazine { public string id { get; set; } public string title { get; set; } public string rating { get; set; } } ``` Here is how I am doing this now: ``` var jo = JObject.Parse(json); var deserializable = jo.First.First.ToString(); string name; var jp = (JProperty)jo.First; if (jp != null) name = jp.Name; var person = JsonConvert.DeserializeObject<Person>(deserializable); person.name = name; ``` This works OK, but I was wondering, maybe it could be done better by using a custom JsonConverter? I'm afraid this is a little bit over my head atm, so I am asking here for some help... Anyway, if there is any better way to achieve this, please share.

Original source