2017-02-01 27 views
1

我有一個客戶端可以調用兩個不同版本的服務。將兩個值反序列化到同一個屬性

一個服務只發送一個值:

{ 
    "value" : { ... } 
} 

第二服務始終返回多個值:

{ 
    "values" : [ 
    { ... }, 
    { ... } 
    ] 
} 

理想情況下,我想在我的客戶一個對象來表示此類,因此用戶永遠不會看到它是單個值還是多個值。

public class MyValues 
{ 
    public List<Stuff> Values { get; set; } 
    public Thing Other { get; set; } 
} 

我認爲,只有這樣,我就可以做到這一點是我將適用於MyValues定製JsonConverter類,但我真的只是想要做一些自定義的,當我反序列化屬性value 。我似乎無法弄清楚如果IContractResolver將是一個更好的方式去(如幻影財產莫名其妙地附加到反序列value,並把它變成Values MyValues。

如果我創建一個自定義轉換器,怎麼樣到我告訴它通常反序列化一切(例如,如果Other有一個額外的屬性,確保他們得到妥善處理等)

+0

你可以寫一個轉換器和映射到一個或另一個取決於它是什麼類型。類似的問題:[反序列化JSON屬性爲布爾或雙](http://stackoverflow.com/q/39347858/1070452) – Plutonix

回答

1

爲了讓這個具有特殊的處理一類的一些屬性,但使用默認處理了剩餘的custom JsonConverter,您可以將JSON裝載到JObject,分離和處理的自定義屬性,然後填充從JObject餘與JsonSerializer.Populate(),如下所示:

class MyValuesConverter : CustomPropertyConverterBase<MyValues> 
{ 
    protected override void ProcessCustomProperties(JObject obj, MyValues value, JsonSerializer serializer) 
    { 
     // Remove the value property for manual deserialization, and deserialize 
     var jValue = obj.GetValue("value", StringComparison.OrdinalIgnoreCase).RemoveFromLowestPossibleParent(); 
     if (jValue != null) 
     { 
      (value.Values = value.Values ?? new List<Stuff>()).Clear(); 
      value.Values.Add(jValue.ToObject<Stuff>(serializer)); 
     } 
    } 
} 

public abstract class CustomPropertyConverterBase<T> : JsonConverter where T : class 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return typeof(T).IsAssignableFrom(objectType); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     if (reader.TokenType == JsonToken.Null) 
      return null; 
     var jObj = JObject.Load(reader); 
     var contract = (JsonObjectContract)serializer.ContractResolver.ResolveContract(objectType); 
     var value = existingValue as T ?? (T)contract.DefaultCreator(); 

     ProcessCustomProperties(jObj, value, serializer); 

     // Populate the remaining properties. 
     using (var subReader = jObj.CreateReader()) 
     { 
      serializer.Populate(subReader, value); 
     } 

     return value; 
    } 

    protected abstract void ProcessCustomProperties(JObject obj, T value, JsonSerializer serializer); 

    public override bool CanWrite { get { return false; } } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     throw new NotImplementedException(); 
    } 
} 

public static class JsonExtensions 
{ 
    public static JToken RemoveFromLowestPossibleParent(this JToken node) 
    { 
     if (node == null) 
      return null; 
     var contained = node.AncestorsAndSelf().Where(t => t.Parent is JContainer && t.Parent.Type != JTokenType.Property).FirstOrDefault(); 
     if (contained != null) 
      contained.Remove(); 
     // Also detach the node from its immediate containing property -- Remove() does not do this even though it seems like it should 
     if (node.Parent is JProperty) 
      ((JProperty)node.Parent).Value = null; 
     return node; 
    } 
} 
1

而不是寫一個JsonConverter,你可以做一組,唯一的財產ValueMyValues,像這樣:

public class MyValues 
{ 
    [JsonProperty] 
    Stuff Value 
    { 
     set 
     { 
      (Values = Values ?? new List<Stuff>(1)).Clear(); 
      Values.Add(value); 
     } 
    } 

    public List<Stuff> Values { get; set; } 
    public Thing Other { get; set; } 
} 

如果標記爲[JsonProperty],它可能是公開或私人的。在這種情況下,如果在JSON中遇到單例"value"屬性,則Json.NET將調用Value setter,如果遇到數組"values",則調用Values setter。由於該屬性已設置 - 只有數組屬性將被重新序列化。

+0

這是一個很好的簡單解決方案,我的問題。我不把它作爲答案的唯一原因是這個問題稍微適合製作一個JsonConverter。這也很好地解決了我的問題。 –

相關問題