Reputation: 57
Let's say that I want to make a winform page that receives a certain amount of random features read from the contents of a json file. (while using the 'Newtonsoft.Json' library)
Code that Deserializes the json file
Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(File.ReadAllText(@"..\..\Json\features.json"));
These classes are set to represent the contents and structure of the json file within the same c# file, but outside of the main class of course.
class Root
{
public List<Category> category { get; set; }
}
class Category
{
public string name { get; set; }
public List<Feature> feature { get; set; }
}
class Feature
{
public string name { get; set; }
public string frequency { get; set; }
}
I have followed the practices to make this happen here:
It works, however there are two main problems I can see with this:
My question: Is there a way to deserialize the json file without having to resort to creating multiple classes for every sub-category of data in the json string?
Upvotes: 1
Views: 2133
Reputation: 35057
I believe that best practice is using classes.
Here are my arguments for using classes in your case:
dynamic
(ugh) but it think your code should depend on a class (a dto) not on a json string. This input structure happens to be stored in json, but may not be. Most of your unit tests should take in an object, not a string.Upvotes: 1
Reputation: 51
I believe you don't need the classes, because you don't need the whole JSON string, is that correct?
If so, instead of deserializing the whole json file, you could partially deserialize only the parts which you are interested in.
Have a look at this example from the Newtonsoft.Json documentation, where we have a long json string representing a response from a Google search, but are only interested in the responseData/results
part of it, and only in some fields of that result object:
Object to partially desierialize:
public class SearchResult
{
public string Title { get; set; }
public string Content { get; set; }
public string Url { get; set; }
}
Deserializing Partial JSON Fragment Example:
string googleSearchText = @"{
'responseData': {
'results': [
{
'GsearchResultClass': 'GwebSearch',
'unescapedUrl': 'http://en.wikipedia.org/wiki/Paris_Hilton',
'url': 'http://en.wikipedia.org/wiki/Paris_Hilton',
'visibleUrl': 'en.wikipedia.org',
'cacheUrl': 'http://www.google.com/search?q=cache:TwrPfhd22hYJ:en.wikipedia.org',
'title': '<b>Paris Hilton</b> - Wikipedia, the free encyclopedia',
'titleNoFormatting': 'Paris Hilton - Wikipedia, the free encyclopedia',
'content': '[1] In 2006, she released her debut album...'
},
{
'GsearchResultClass': 'GwebSearch',
'unescapedUrl': 'http://www.imdb.com/name/nm0385296/',
'url': 'http://www.imdb.com/name/nm0385296/',
'visibleUrl': 'www.imdb.com',
'cacheUrl': 'http://www.google.com/search?q=cache:1i34KkqnsooJ:www.imdb.com',
'title': '<b>Paris Hilton</b>',
'titleNoFormatting': 'Paris Hilton',
'content': 'Self: Zoolander. Socialite <b>Paris Hilton</b>...'
}
],
'cursor': {
'pages': [
{
'start': '0',
'label': 1
},
{
'start': '4',
'label': 2
},
{
'start': '8',
'label': 3
},
{
'start': '12',
'label': 4
}
],
'estimatedResultCount': '59600000',
'currentPageIndex': 0,
'moreResultsUrl': 'http://www.google.com/search?oe=utf8&ie=utf8...'
}
},
'responseDetails': null,
'responseStatus': 200
}";
// Parse JSON into a JObject, which we can easily traverse
JObject googleSearch = JObject.Parse(googleSearchText);
// get JSON result objects into a list
IList<JToken> results = googleSearch["responseData"]["results"].Children().ToList();
// serialize JSON results into .NET objects
IList<SearchResult> searchResults = new List<SearchResult>();
foreach (JToken result in results)
{
// JToken.ToObject is a helper method that uses JsonSerializer internally
SearchResult searchResult = result.ToObject<SearchResult>();
searchResults.Add(searchResult);
}
// Title = <b>Paris Hilton</b> - Wikipedia, the free encyclopedia
// Content = [1] In 2006, she released her debut album...
// Url = http://en.wikipedia.org/wiki/Paris_Hilton
// Title = <b>Paris Hilton</b>
// Content = Self: Zoolander. Socialite <b>Paris Hilton</b>...
// Url = http://www.imdb.com/name/nm0385296/
This way, we only need to create a class for SearchResult
and for nothing else, which sounds like what you want to have. While traversing the JSON object with code like googleSearch["responseData"]["results"]
you can check whether the result is null and act accordingly, which means you can have optional fields in your JSON file, which are not present in other files, without your code breaking.
Does this help you solve your issues?
Upvotes: 1