2013-10-03 110 views
2

我已經閱讀json.net上的文檔相當好,並且我正在用盡想法。我有一種情況,我有孩子提及那裏的父母。所以從屬性Json.Net自定義序列化

public class ObjA 
{ 
    public int Id {get;set} 
    public string OtherStuff {get;set} 
    public ObjB MyChild {get;set} 
} 

public class ObjB 
{ 
    public int Id {get;set} 
    public string OtherStuff {get;set} 
    public ObjA MyParent {get;set} 
} 

這不會序列化。所以我可以做[JsonIgnore],但我更願意做的是[JsonIdOnly]其中ObjB,而不是MyParent的序列化或跳過MyParent,完全顯示MyParentId的123屬性。所以

{OjbA:{ 
    Id:123, 
    OtherStuff:some other stuff, 
    MyChild:{ 
     Id:456, 
     OtherStuff:Some other stuff, 
     MyParentId:123, 
     } 
    } 
} 

我知道我可以寫一個類型的自定義轉換器。問題是我希望只有在指定時纔會發生這種情況,否則我將無法序列化ObjA。換句話說,我需要這個纔會發生,只有當我用一個屬性裝飾它。所以

public class ObjB 
{ 
    public int Id {get;set} 
    public string OtherStuff {get;set} 
    [JsonIdOnly] 
    public ObjA MyParent {get;set} 
} 

感謝, RAIF

回答

2

如果你不關心你的JSON中有一些額外的簿記信息,然後在JsonSerializerSettingsAll(或Objects)設置PreserveReferenceHandling選項,@Athari建議。這是使其工作的最簡單方法。如果你這樣做,你的JSON應該是這樣的:

{ 
    "$id": "1", 
    "Id": 123, 
    "OtherStuff": "other stuff A", 
    "MyChild": { 
    "$id": "2", 
    "Id": 456, 
    "OtherStuff": "other stuff B", 
    "MyParent": { 
     "$ref": "1" 
    } 
    } 
} 

這就是說,有一種方法做你原來想要的東西,使用自定義JsonConverter。你可以做的是製作一個轉換器,它將接受任何具有Id屬性的對象。然後,對於那些您希望將其僅序列化爲ID的地方,可以使用[JsonConverter]屬性修飾這些屬性。自定義轉換器將用於這些情況,但不會以其他方式使用。以下是轉換器的外觀:

class IdOnlyConverter : JsonConverter 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return objectType.IsClass; 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     writer.WriteStartObject(); 
     writer.WritePropertyName("Id"); 
     writer.WriteValue(GetId(value)); 
     writer.WriteEndObject(); 
    } 

    private int GetId(object obj) 
    { 
     PropertyInfo prop = obj.GetType().GetProperty("Id", typeof(int)); 
     if (prop != null && prop.CanRead) 
     { 
      return (int)prop.GetValue(obj, null); 
     } 
     return 0; 
    } 

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

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

要使用轉換器,您需要按照您的說明設置類。請注意0​​如何用屬性修飾來告訴Json.Net使用該屬性的自定義轉換器。

public class ObjA 
{ 
    public int Id { get; set; } 
    public string OtherStuff { get; set; } 
    public ObjB MyChild { get; set; } 
} 

public class ObjB 
{ 
    public int Id { get; set; } 
    public string OtherStuff { get; set; } 
    [JsonConverter(typeof(IdOnlyConverter))] 
    public ObjA MyParent { get; set; } 
} 

序列化時,您將需要的JsonSerializerSettingsReferenceLoopHandling選項設置爲Serialize告訴Json.Net如果檢測到參考迴路不是拋出一個錯誤,並繼續反正序列化(因爲我們的轉換器將處理它)。

全部放在一起,這裏是一些示例代碼演示了正在運行的轉換器:

class Program 
{ 
    static void Main(string[] args) 
    { 
     ObjA a = new ObjA(); 
     a.Id = 123; 
     a.OtherStuff = "other stuff A"; 

     ObjB b = new ObjB(); 
     b.Id = 456; 
     b.OtherStuff = "other stuff B"; 
     b.MyParent = a; 

     a.MyChild = b; 

     JsonSerializerSettings settings = new JsonSerializerSettings 
     { 
      ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Serialize, 
      Formatting = Newtonsoft.Json.Formatting.Indented 
     }; 

     string json = JsonConvert.SerializeObject(a, settings); 
     Console.WriteLine(json); 
    } 
} 

這裏是上面的輸出:

{ 
    "Id": 123, 
    "OtherStuff": "other stuff A", 
    "MyChild": { 
    "Id": 456, 
    "OtherStuff": "other stuff B", 
    "MyParent": { 
     "Id": 123 
    } 
    } 
} 
+0

哦,好的,是的,我創建了一個轉換器,但不知道如何讓他進入屬性。這將工作正常。感謝你們兩位。 – Raif

+0

嗨,所以一切都很好,除了我得到這個錯誤{「Message」:「發生錯誤」, 「ExceptionMessage」:「'ObjectContent'1'類型未能序列化內容類型的響應主體'application/json; charset = utf-8'。「, 」ExceptionType「:」System.InvalidOperationException「, 」StackTrace「:null, 」InnerException「:{ 」Message「:」發生錯誤。 , 「ExceptionMessage」:「錯誤創建GuidEntityToIdJsonConverter」, 「ExceptionType」:「Newtonsoft.Json.JsonException」, – Raif

+0

哇抱歉缺乏在這個堆棧跟蹤結束格式化 – Raif

0

您可以更改JsonSerializerSettings.PreserveReferencesHandlingPreserveReferencesHandling.ObjectsPreserveReferencesHandling.All(你可能還需要改變​​和各種JsonPropertyAttribute關於引用屬性)。這將爲對象添加$ref JSON屬性,交叉鏈接將被保留。

您可以使用自定義IReferenceResolver修改$ref屬性的文本。

但是,如果您需要更復雜的引用來解析(如您所建議的引用),而沒有$ref屬性,則必須編寫一些代碼。

+0

謝謝大家的響應。我沒有看到這些屬性,正在調查。不過,我很樂意編寫一些代碼來獲得我想要的。我只是無法從customConverter和converterAttribute中弄明白。我現在正在閱讀上面的道具(實際上我正要去吃午飯,但之後),目的是弄清楚如何編寫自己的擴展。如果你碰巧知道正確的方向,那麼知道這很好。再次感謝,raif – Raif

+0

真的很快,我去吃午飯它看起來像ReferenceLoopHandling是非常接近。如果我可以繼承它,或者通過一些完美的機制擴展它。 – Raif

+0

如果你的JSON看起來並不重要,我建議堅持'$ ref'屬性。我在[我的私人框架](https://github.com/Athari/Alba.Framework/tree/master/Alba.Framework.Serialization.Json)中實現了自定義引用,但是我擔心它太複雜了一個很好的樣本。它會像上面建議的那樣建立鏈接,但它需要很多屬性和一些自定義代碼;沒有文檔。 :) – Athari

相關問題