2014-10-17 62 views
13

我在使用Newtonsoft.Json從我的ASP.NET Web API控制器正確序列化一些數據時遇到問題。如何「真的」用Newtonsoft.Json序列化循環引用對象?

這是我的認爲正在進行 - 請糾正我,如果我錯了。在某些情況下(特別是當數據中沒有任何循環引用時),所有內容都可以像您期望的那樣工作 - 將填充的對象列表序列化並返回。如果我在模型中引入了導致循環引用的數據(如下所述,並且即使設置了PreserveReferencesHandling.Objects),也只有列表中帶有循環引用的第一個對象的列表元素被序列化,客戶端可以「與」。如果在將數據發送到序列化程序之前,「引導到的元素」可以是數據中的任何元素,但是至少有一個元素將以客戶端可以「使用」的方式進行序列化。空對象最終被序列化爲Newtonsoft引用({$ref:X})。

舉例來說,如果我有一個EF模型完整的導航性能,看起來像這樣:

Model

在我的Global.asax:

var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter; 
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects; 

這裏的基本查詢我m使用實體框架(懶加載關閉,所以這裏沒有任何代理類):

[HttpGet] 
[Route("starting")] 
public IEnumerable<Balance> GetStartingBalances() 
{ 
    using (MyContext db = new MyContext()) 
    { 
     var data = db.Balances 
     .Include(x => x.Source) 
     .Include(x => x.Place) 
     .ToList() 
     return data; 
    } 
} 

到目前爲止好,data已填充。

如果沒有循環引用,生活就是盛大。但是,只要存在具有相同SourcePlace的實體,那麼序列化會將我返回到Newtonsoft引用的最頂級列表的後續對象變成Newtonsoft引用,而不是其完整對象,因爲它們已經是連載中SourcePlace對象(S)的Balances屬性:

[{"$id":"1","BalanceID":4,"SourceID":2,"PlaceID":2 ...Omitted for clarity...},{"$ref":"4"}] 

這樣做的問題是客戶不知道做什麼用{$ref:4}即使我們人類明白這是怎麼回事。在我的情況下,這意味着我無法使用AngularJS以ng-repeat在我的整個天平列表中使用此JSON,因爲它們並非都是Balance對象,而要綁定Balance屬性。我敢肯定,還有很多其他使用案例會有相同的問題。

我無法關閉json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects,因爲很多其他事情都會中斷(這裏有100個其他問題詳細記錄)。

是否有這更好的解決辦法除了通過在Web API控制器的實體去,做

Balance.Source.Balances = null; 

到所有的導航性能,打破循環引用?因爲這看起來不正確。

回答

15

是的,使用PreserveReferencesHandling.Objects實際上是序列化循環引用的對象圖形的最好方法,因爲它生成最緊湊的JSON,並且實際上保留了對象圖的參考結構。也就是說,當您將JSON反序列化爲對象(使用瞭解$id$ref表示法的庫)時,對特定對象的每個引用都將指向該對象的同一實例,而不是具有多個具有相同數據的實例。

在你的情況下,問題是你的客戶端解析器不理解由Json.Net生成的$id$ref表示法,所以引用沒有被解析。這可以通過使用javascript方法在反序列化JSON之後重建對象引用來解決。示例見herehere

可能工作,根據您的情況還有一種可能,是不是序列化設置PreserveReferencesHandlingObjects時設置ReferenceLoopHandlingIgnore。但這不是一個完美的解決方案。有關使用ReferenceLoopHandling.IgnorePreserveReferencesHandling.Objects之間差異的詳細說明,請參見this question

相關問題