为什么 序列化类型为“System.Data.Entity.DynamicProxies.Photos....这个会的对象时检测到循环引用。
今天遇到下面这个问题,小子留了下来供大家参考
“/”应用程序中的服务器错误。
序列化类型为“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方法)决定那些属性要输出.