2017-12-09 4 views
0

JavaScript/PHP Veteran, .NET Newbie hier.Wie JSON mit inkonsistentem Schema deserialisieren

Ich versuche, Json.NET zu verwenden, um JSON-Daten, die von einem API-Aufruf zurückgegeben werden, in einigen Klasseninstanzen zu deserialisieren.

Es funktioniert gut für die meisten API-Aufrufe, wenn das JSON-Schema konsistent ist und meinen Klassen entspricht. Aber ich habe ein paar JSON-Objekte, die wie folgt zurück:

"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":{ ... } },

Was ist die beste Methode, ein inkonsistentes Schemas für die Handhabung, wie „Sucher“?

Ich habe ein "SearchResult" erstellt, das eine "Zusammenfassung" -Eigenschaft hat, aber ich bin mir nicht sicher, wie die restlichen Elemente zugeordnet werden.

+0

Wenn Sie sagen, dass es inkonsistent ist, meinen Sie, dass es eine unterschiedliche Anzahl von Relevanz/Id-Paaren gibt? Sonst ist nichts inkonsequent, wenn wir nur eins sehen können. – Plutonix

+1

Sie können in einem anonymen Objekt deserialisieren. Beziehen Sie sich auf diese Antwort https://StackOverflow.com/a/33284670/8438534 –

+0

Es denken, dass es inkonsistent ist, weil Sie eine variierende Anzahl von integralen Eigenschaften und eine einzige benannte Eigenschaft "Zusammenfassung" innerhalb des "searchresult" -Objekts haben. Ich würde mir vorstellen, dass es besser wäre mit einer benannten Eigenschaft "Zusammenfassung" und einem Array von Schlüsselpaaren. – Firephp

Antwort

2

Um Ihnen starke Typisierung zu geben, wenn das Schema ist immer mit einem:

  • Zusammenfassung
  • unterschiedliche Anzahl von „Relevanzen“

Sie können eine JsonConverter Klasse es deserialisieren in eine Klasse namens Zusammenfassung und eine Liste von "Relevances". Wie so:

Ausführung:

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(); 
    } 
} 

Es gibt mehrere Möglichkeiten, dies in ReadJson zu tun, sowie andere Möglichkeiten der Deserialisierung mit Json.Net, aber ich finde auf diese Weise lesbar genug, um zu verstehen, was vor sich geht.

+0

Sehr gut lesbar. Am Ende habe ich diese Lösung verwendet. Vielen Dank! – Firephp