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.