https://www.bbsmax.com/A/Vx5MvaGadN/
模型中有循環引用是很常見的。例如,以下模型顯示雙向導航屬性:
- : public class Category
- : {
- : public Category()
- : {
- : Products = new Collection<Product>();
- : }
- :
- : public int Id { get; set; }
- : public string Name { get; set; }
- : public virtual ICollection<Product> Products { get; set; }
- : }
- :
- : public class Product
- : {
- : public int Id { get; set; }
- : public string Name { get; set; }
- : public virtual Category Category { get; set; }
- : }
通過生成EF API控制器與Web API一起使用時,默認情況下不起作用。使用json.net序列化器序列化時會發生以下錯誤:
Self referencing loop detected for property 'Category' with type
'System.Data.Entity.DynamicProxies.Category_A97AC61AD05BA6A886755C779FD3F96E86FE903ED7C9BA9400E79162C11BA719'.
Path '[0].Products[0]'
發生此錯誤是因為序列化程序不知道如何處理循環引用。(在xml序列化程序中也出現類似的錯誤)
禁用代理並包含引用
EF代理不適用於POCO數據序列化。有幾種 解決方法。為了簡單起見,我們只是在數據上下文類中禁用它:
- : public CircularReferenceSampleContext() : base("name=CircularReferenceSampleContext")
- : {
- : Database.SetInitializer(new CircularReferenceDataInitializer());
- : this.Configuration.LazyLoadingEnabled = false;
- : this.Configuration.ProxyCreationEnabled = false;
- : }
但是,在禁用代理之后,導航屬性不會被延遲加載。因此,從數據庫中檢索數據時必須包含參考。將腳手架控制器代碼更改為:
- : public IEnumerable <Product> GetProducts()
- : {
- : return db.Products.Include(p => p.Category).AsEnumerable();
- : }
包含調用將包含所有記錄的參考數據。
修復1:全局忽略循環引用
json.net序列化器支持忽略全局設置的循環引用。一個快速解決方案是將下面的代碼放在WebApiConfig.cs文件中:
- : config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
簡單的修復將使序列化程序忽略會導致循環的引用。但是,它有局限性:
- 數據丟失循環參考信息
- 該修補程序僅適用於JSON.net
- 如果存在深度參考鏈,則無法控制參考級別
修復2:保留全局循環引用
第二個修復與第一個類似。只需將代碼更改為:
- : config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling
- : = Newtonsoft.Json.ReferenceLoopHandling.Serialize;
- : config.Formatters.JsonFormatter.SerializerSettings.PreserveReferencesHandling
- : = Newtonsoft.Json.PreserveReferencesHandling.Objects;
數據形狀將在應用此設置后更改。
- : [{ “$ ID” :“” , “類別”:{ “$ ID” :“” , “產品”:[{ “$ ID” :“” , “類別”:{ “$ REF “:”“ },”ID“:, ” 名稱“:”酸奶“ },{ ”$ REF“ :”“ }],”ID“:, ” 名稱“:”日記“ }, ” Id“:,“名稱”:“全脂牛奶” },{ “$ ” }]
$ id和$ ref保留所有引用,並使對象圖級別保持不變,但客戶端代碼需要知道形狀更改以消費數據,並且它僅適用於JSON.NET序列化程序。
修復3:忽略並保留參考屬性
此修補程序在模型類上裝飾屬性以控制模型或屬性級別上的序列化行為。忽略該屬性:
- : public class Category
- : {
- : public int Id { get; set; }
- : public string Name { get; set; }
- :
- : [JsonIgnore]
- : [IgnoreDataMember]
- : public virtual ICollection<Product> Products { get; set; }
- : }
為了保持參考:
- : // Fix 3
- : [JsonObject(IsReference = true)]
- : public class Category
- : {
- : public int Id { get; set; }
- : public string Name { get; set; }
- :
- : // Fix 3
- : //[JsonIgnore]
- : //[IgnoreDataMember]
- : public virtual ICollection<Product> Products { get; set; }
- : }
- :
- : [DataContract(IsReference = true)]
- : public class Product
- : {
- : [Key]
- : public int Id { get; set; }
- :
- : [DataMember]
- : public string Name { get; set; }
- :
- : [DataMember]
- : public virtual Category Category { get; set; }
- : }
[JsonObject(IsReference = true)]適用於JSON.NET,[DataContract(IsReference = true)]適用於XmlDCSerializer。請注意:在類上應用DataContract后,您需要將DataMember添加到要序列化的屬性。
這些屬性可以應用於json和xml序列化器,並且可以為模型類提供更多的控制。
參考官方解決方案:https://code.msdn.microsoft.com/Loop-Reference-handling-in-caaffaf7
________________________________________________________________________________________________
c# – JSON.Net自我引用循環檢測
當我使用這個:
public static string GetAllEventsForJSON() { using (CyberDBDataContext db = new CyberDBDataContext()) { return JsonConvert.SerializeObject((from a in db.Events where a.Active select a).ToList(), new JavaScriptDateTimeConverter()); } }
代碼導致以下錯誤:
Newtonsoft.Json.JsonSerializationException: Self referencing loop detected for property ‘CyberUser’ with type ‘DAL.CyberUser’.
Path ‘[0].EventRegistrations[0].CyberUser.UserLogs[0]’.
我只想顯示父收集項列表,不需要任何子數據,因此我使用以下和它工作正常:
JsonConvert.SerializeObject(ResultGroups, Formatting.None,
new JsonSerializerSettings()
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
});
JSON.NET Error Self referencing loop detected for type
它還參考了Json.NET代碼段頁面: