2015-10-20 104 views
0

我正在尋找一種方法,使用Json.Net將模型部分序列化爲Json。部分序列化應該如何看起來像我想要定義父對象的屬性。所以對於不同的父模型,部分序列化看起來可能不同。爲了說明什麼,我想在這裏的一些代碼:基於屬性屬性的模型部分序列化

private class MyTestObject 
{ 
    [SerializeOnly("TestValue1")] 
    [SerializeOnly("TestValue3")] 
    public ComplexTestObject Property1 { get; set; } 

    public MyTestObject() 
    { 
     Property1 = new ComplexTestObject(); 
    } 
} 

private class ComplexTestObject 
{ 
    public string TestValue1 { get; set; } 
    public string TestValue2 { get; set; } 
    public string TestValue3 { get; set; } 
    public ComplexTestObject() 
    { 
     TestValue1 = "value1"; 
     TestValue2 = "value2"; 
     TestValue3 = "value3"; 
    } 
} 

現在,當我序列MyTestObject類的實例,我想以下JSON:

{ 
    "Property1" : { 
     "TestValue1" : "value1", 
     "TestValue3" : "value3", 
    } 
} 

你可以看到SerializeOnly被用來定義屬性將被序列化。

爲了達到這個目的,我可以創建一個SerializeOnlyAttribute。當試圖在自定義Serialization ContractResolver中使用它時,我只能看到特定成員的屬性,所以我看不到任何SerializeOnlyAttribute,因爲它們駐留在父級上。

有沒有一種簡單的方法來實現與Json.Net所需的行爲?有可能編寫一個自定義的JsonConverter,但是如何構建它,使得只處理屬性被覆蓋,並仍然使用默認轉換器?

回答

1

可以分爲兩個部分解決這個問題:

  • 創建一個自定義JsonConverter可以接受的列表要序列化的屬性的名稱。
  • 創建一個自定義ContractResolver,查找至少應用了一個[SerializeOnly]屬性的屬性,並將自定義轉換器應用於這些屬性,並傳遞從應用屬性收集的子屬性名稱列表。

這裏是解析器可能是什麼樣子:

class CustomResolver : DefaultContractResolver 
{ 
    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization) 
    { 
     IList<JsonProperty> props = base.CreateProperties(type, memberSerialization); 
     foreach (JsonProperty prop in props) 
     { 
      if (!prop.PropertyType.IsPrimitive && prop.PropertyType != typeof(string)) 
      { 
       PropertyInfo pi = type.GetProperty(prop.UnderlyingName); 
       if (pi != null && pi.CanRead) 
       { 
        var childPropertiesToSerialize = pi.GetCustomAttributes<SerializeOnly>() 
                 .Select(att => att.PropertyName); 
        if (childPropertiesToSerialize.Any()) 
        { 
         prop.Converter = new CustomConverter(childPropertiesToSerialize); 
        } 
       } 
      } 
     } 
     return props; 
    } 
} 

這裏是轉換器:

class CustomConverter : JsonConverter 
{ 
    private HashSet<string> propertiesToSerialize; 

    public CustomConverter(IEnumerable<string> propertiesToSerialize) 
    { 
     this.propertiesToSerialize = new HashSet<string>(propertiesToSerialize); 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     writer.WriteStartObject(); 
     foreach (PropertyInfo prop in value.GetType().GetProperties()) 
     { 
      if (prop.CanRead && propertiesToSerialize.Contains(prop.Name)) 
      { 
       writer.WritePropertyName(prop.Name); 
       serializer.Serialize(writer, prop.GetValue(value)); 
      } 
     } 
     writer.WriteEndObject(); 
    } 

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     throw new NotImplementedException(); 
    } 

    public override bool CanConvert(Type objectType) 
    { 
     throw new NotImplementedException(); 
    } 
} 

演示:

class Program 
{ 
    static void Main(string[] args) 
    { 
     var test = new MyTestObject(); 
     var settings = new JsonSerializerSettings(); 
     settings.ContractResolver = new CustomResolver(); 
     settings.Formatting = Formatting.Indented; 
     var json = JsonConvert.SerializeObject(test, settings); 
     Console.WriteLine(json); 
    } 

    class MyTestObject 
    { 
     [SerializeOnly("TestValue1")] 
     [SerializeOnly("TestValue3")] 
     public ComplexTestObject Property1 { get; set; } 

     [SerializeOnly("TestValue2")] 
     public ComplexTestObject Property2 { get; set; } 

     public MyTestObject() 
     { 
      Property1 = new ComplexTestObject(); 
      Property2 = new ComplexTestObject(); 
     } 
    } 

    class ComplexTestObject 
    { 
     public string TestValue1 { get; set; } 
     public string TestValue2 { get; set; } 
     public string TestValue3 { get; set; } 
     public ComplexTestObject() 
     { 
      TestValue1 = "value1"; 
      TestValue2 = "value2"; 
      TestValue3 = "value3"; 
     } 
    } 
} 

輸出:

{ 
    "Property1": { 
    "TestValue1": "value1", 
    "TestValue3": "value3" 
    }, 
    "Property2": { 
    "TestValue2": "value2" 
    } 
} 

小提琴:https://dotnetfiddle.net/Fj7QcW

+0

太棒了!我喜歡這個解決方案! Thx :-) – Sjoerd222888

+0

沒問題;很高興我能幫上忙。 –