Reputation: 1083
I want to deserialize JSON data (using Newtonsoft) similar to following, and convert to a strongly-typed object/list in C#, but can't figure out how to define the class such that indexed references are converted to the referenced objects.
{
"Countries": [
{
"Name": "USA",
},
{
"Name": "UK",
},
{
"Name": "JAPAN",
},
],
"Authors": [
{
"DisplayName": "John Doe",
"RealName": "Not John Doe"
},
{
"DisplayName": "Jane Doe",
"RealName": "Not Jane Doe"
},
],
"Books": [
{
"Author": 0,
"Title": "A good read",
"PublishedCountries": "0,1",
},
{
"Author": 0,
"Title": "Another good read",
"PublishedCountries": "0,1",
},
{
"Author": 1,
"Title": "This one is even better",
"PublishedCountries": "0,1,2",
},
],
}
Ideally, I'd like to use classes similar to following:
public class Country
{
public string Name { get; set;}
}
public class AuthorDetails
{
public string DisplayName { get; set; }
public string RealName { get; set; }
}
public class Book
{
public AuthorDetails Author { get; set; }
public string Title { get; set; }
public IEnumerable<Country> PublishedCountries { get; set; }
}
public class ListOfBooks
{
public IEnumerable<Book> Books { get; set; }
}
And deserialize like this:
var listOfBooks = JsonConvert.DeserializeObject<ListOfBooks>(jsonAsString);
I'm stuck as how to tell Json.Net that the Author property in the book JObject is an index, rather than an integer. Same goes for the PublishedCountries (that's comma-separated list of indexes)
Upvotes: 3
Views: 262
Reputation: 116168
I can't see a way other than helping the deserialization process a little bit.
var dynObj = (JObject)JsonConvert.DeserializeObject(json);
var authors = dynObj["Authors"]
.Select(j => new AuthorDetails {
RealName = (string)j["RealName"],
DisplayName = (string)j["DisplayName"]
})
.ToList();
var countries = dynObj["Countries"]
.Select(j => new Country { Name = (string)j["Name"]})
.ToList();
var books = dynObj["Books"].Select(x => new Book
{
Author = authors[(int)x["Author"]],
Title = (string)x["Title"],
PublishedCountries = x["PublishedCountries"].ToString().Split(',')
.Select(i =>countries[int.Parse(i)])
.ToList()
})
.ToList();
public class Country
{
public string Name { get; set; }
}
public class AuthorDetails
{
public string DisplayName { get; set; }
public string RealName { get; set; }
}
public class Book
{
public AuthorDetails Author { get; set; }
public string Title { get; set; }
public List<Country> PublishedCountries { get; set; }
}
Upvotes: 1
Reputation: 4227
I believe what you want to do is 'preserve object references'.
You can mark-up your C# object with attributes to describe when to utilise a reference, rather than duplicate the content of the object all over again:
[JsonObject(IsReference = true)]
(use on the type declaration)
However, your generated Javascript will not look quite like what you have demonstrated, take a look here to see how to do it.
http://james.newtonking.com/projects/json/help/?topic=html/PreserveObjectReferences.htm
Instead, your JSON will look more like this:
{
"Countries": [
{
"Name": "USA",
},
{
"Name": "UK",
},
{
"Name": "JAPAN",
},
],
"Authors": [
{
"DisplayName": "John Doe",
"RealName": "Not John Doe"
},
{
"DisplayName": "Jane Doe",
"RealName": "Not Jane Doe"
},
],
"Books": [
{
"$id": 1,
"Author": 0,
"Title": "A good read",
"PublishedCountries": "0,1",
},
{
"$ref": 1
},
{
"Author": 1,
"Title": "This one is even better",
"PublishedCountries": "0,1,2",
},
],
}
Upvotes: 0