Reputation: 157
JavaScript/PHP Veteran, .NET Newbie here.
I'm trying to use Json.NET to deserialize JSON data, returned from an API call, into some class instances.
It works well for most API calls when the JSON schema is consistent and matches my classes. However, I have a few JSON objects that return like this:
"searchresult":{
"summary":{
"page":"1 of 451",
"relevancy":"100% - 99%",
"count":25,
"query":"some search query"
},
"0":{
"relevance":100,
"id":343,
},
"1":{
"relevance":99,
"id":434,
},
"2":{
...
}
},
What is the best method for handling an inconsistent schema, like "searchresult"?
I have created a "SearchResult", which has a "Summary" property, however I'm not sure how to map the remaining items.
Upvotes: 0
Views: 979
Reputation: 549
In order to give you strong typing, if the schema is always with a:
You can a JsonConverter class to deserialize it into a class named Summary, and a List of "Relevances". Like so:
Execution:
string json = @"{
""searchresult"":{
""summary"":{
""page"":""1 of 451"",
""relevancy"":""100% - 99%"",
""count"":25,
""query"":""some search query""
},
""0"":{
""relevance"":100,
""id"":343,
},
""1"":{
""relevance"":99,
""id"":434,
}
}
}";
var searchResult = JsonConvert.DeserializeObject<SearchResult>(json);
ViewModels
[JsonConverter(typeof(Converter))]
class SearchResult
{
public Summary Summary { get; set; }
public List<RelevanceWrapper> Relevances { get; set; }
}
class Summary
{
public string Page { get; set; }
public string Relevancy { get; set; }
public int Count { get; set; }
public string Query { get; set; }
}
class RelevanceWrapper
{
public int Id { get; set; }
public int Relevance { get; set; }
}
JsonConverter
class Converter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jObject = JObject.Load(reader);
var searchResultToken = jObject.GetValue("searchresult");
var searchResult = new SearchResult()
{
Relevances = new List<RelevanceWrapper>()
};
foreach (JProperty prop in searchResultToken)
{
if (prop.Name == "summary")
{
searchResult.Summary = prop.Value.ToObject<Summary>();
}
else
{
searchResult.Relevances.Add(prop.Value.ToObject<RelevanceWrapper>());
}
}
return searchResult;
}
public override bool CanConvert(Type objectType)
{
throw new NotImplementedException();
}
}
There are more ways to do this in ReadJson, as well as other ways of deserializing with Json.Net, but I find this way readable enough to understand what's going on.
Upvotes: 2