今天遇到下面這個問題,小子留了下來供大家參考
“/”應用程序中的服務器錯誤。
序列化類型為“System.Data.Entity.DynamicProxies.Photos_1F5D250F2735650E782711718DE2EFF2BBEA68EE8F6C5A1CF253FAABD0681F7B”的對象時檢測到循環引用。
源碼如下:
public ActionResult GetAllUserInfos() { //方法內部給前台返回當前頁的數據: json:{total:30,rows:[]} //當前表格會自動發送異步請求到后台,然后傳遞參數是:rows page var pageSize = Request["rows"] == null ? 10 : int.Parse(Request["rows"]); var pageIndex = Request["page"] == null ? 1 : int.Parse(Request["page"]); //當前頁的對象 分頁 var pageData = db.Photos.OrderBy(u => u.PId) .Skip(pageSize * (pageIndex - 1)) .Take(pageSize); //var pageData = db.Photos.ToList(); //為啥有這個對象:前台需要這樣的對象,先組裝成一個匿名類然后序列化 var result = new { total = db.Photos.Count(), rows = pageData }; return Json(result, JsonRequestBehavior.AllowGet); }
在百度查看了下方案,說加一句這個
db.Configuration.ProxyCreationEnabled = false; 我試了一下果然好用,但是不明白,為什么會出現這種錯誤,求各位大神的指導
好像知道了.因為這個表和另一個表是有一對多關系的,當序列化表1的時候,會找到和另一個表2關聯的字段,就會到另一個表2中序列化,然后另一個表2中也有一個字段和表1相關聯.這樣.序列化就會發生這種錯誤! 相關解決方案有3種:
1.最簡單的方式就是從Entity Framework着手,停用LazyLoading與ProxyCreation.因為LazyLoading停用后那么當JSON.Net解析Order對象時其屬性Order_Details會返回null(不會自動加載).所以也就避免了此問題
當然此方式的缺點會導致后續程序存取Entity Object時犧牲了LazyLoading的方便性,需要手動處理此問題.
1.
db.Configuration.LazyLoadingEnabled =
false
;
2.
db.Configuration.ProxyCreationEnabled =
false
;
3.
4.
return
db.Orders.AsEnumerable();
2.設定JSON.Net忽略循環參考
透過APP_Start的WebApiConfig.cs,設定config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
使用這個方式時要注意,它只是忽略循環參考的錯誤,但實際上還是會自動一層層解析要輸出的對象之屬性,所以若數據會相依有可能會產生無窮循環.
3.設定JSON.Net避免循環參考
透過APP_Start的WebApiConfig.cs,設定
config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Serialize;
config.Formatters.JsonFormatter.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
這種做法與2的差異在於它會將重復過的對象用一個代表取代,譬如底下JSON格式
1: [{"$id":"1","Category":{"$id":"2","Products":[{"$id":"3","Category":{"$ref":"2"},"Id":2,"Name":"Yogurt"},{"$ref":"1"}],"Id":1,"Name":"Diary"},"Id":1,"Name":"Whole Milk"},{"$ref":"3"}]
所以對於數據而言這種作法還是會自動一層層解析要輸出的對象之屬性,只是避免輸出太大量數據.
4.手動設定避免循環參考
如同3的模式,透過[JsonIgnore] 與[JsonObject(IsReference = true)] 細部設定,可以更精確的設定每個要輸出的屬性.
缺點是1.設定繁雜. 2.只能通用設定無法例外. 3.因為必須直接或透過 partial class方式設定,故無法將設定與Entity Object class做分離
以上作法實際上都有其優缺點, 並沒有一個可以通用的模式, 須看需求而定,這問題與同早期RIA Service的問題相同,但這邊提供一種比較通用的模式就是采用方法1+方法2或3.
停用LazyLoading,而使用程序的方式(透過 Include方法)決定那些屬性要輸出.