ASP.NET MVC中Json序列化循环引用与重复序列化问题求助
解决ASP.NET MVC返回Json时的循环引用与重复序列化问题
我来帮你搞定这个头疼的问题,这在使用EF的ASP.NET MVC项目里非常常见,咱们一步步拆解原因和解决方案:
错误原因分析
- 循环引用错误:你看到的
DynamicProxies相关错误,是因为EF为了支持延迟加载生成了动态代理对象,这些对象里的导航属性(比如Supplier和InformationSecurityData互相引用)会导致序列化时出现循环引用,陷入死循环。 - 重复序列化问题:当你手动用
JsonConvert.SerializeObject生成Json字符串后,再用return Json(json, ...)返回,JsonResult会把这个字符串当成普通对象再次序列化,导致前端拿到的是被转义的字符串(比如带双引号包裹的Json),解析自然会出错。
解决方案
方案一:关闭EF动态代理(最简单直接)
EF的动态代理是循环引用的根源,我们可以直接关闭它,让查询返回普通实体对象而非代理对象。有两种方式:
方式1:全局关闭(在DbContext中配置)
在你的DbContext构造函数里添加配置:
public YourDbContext() : base("YourConnectionString") { // 关闭动态代理生成 this.Configuration.ProxyCreationEnabled = false; // 可选:关闭延迟加载,避免导航属性自动加载导致的问题 this.Configuration.LazyLoadingEnabled = false; }
方式2:单个查询关闭(局部生效)
如果不想全局关闭,在每个查询后面加上AsNoTracking():
List<InformationSecurityData> iso = db.InformationSecurityDatas.AsNoTracking().Where(x => x.Supplier_ID == id).ToList(); List<SurveyForm> tender = db.SurveyForms.AsNoTracking().Where(x => x.Supplier_ID == id ).ToList(); List<ProcurementData> procurement = db.ProcurementDatas.AsNoTracking().Where(x => x.Supplier_ID == id ).ToList(); List<Supplier> supp = db.Suppliers.AsNoTracking().Where(x => x.Supplier_ID == id).ToList();
这样处理后,直接返回Json(model, JsonRequestBehavior.AllowGet)就不会有循环引用问题了。
方案二:手动序列化后用Content返回(避免重复序列化)
如果你需要保留动态代理,可以手动序列化后用Content返回,跳过JsonResult的自动序列化:
[HttpPost] public ActionResult GetallData(int id) { MultipleViewModel model = new MultipleViewModel(); List<InformationSecurityData> iso = db.InformationSecurityDatas.Where(x => x.Supplier_ID == id).ToList(); List<SurveyForm> tender = db.SurveyForms.Where(x => x.Supplier_ID == id ).ToList(); List<ProcurementData> procurement = db.ProcurementDatas.Where(x => x.Supplier_ID == id ).ToList(); List<Supplier> supp = db.Suppliers.Where(x => x.Supplier_ID == id).ToList(); model.Inf_Sec_Dat = iso; model.Proc_Dat = procurement; model.Tender_Dat = tender; model.Supp_dat = supp; // 配置序列化设置,忽略循环引用 var serializerSettings = new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore, Formatting = Formatting.Indented }; string json = JsonConvert.SerializeObject(model, serializerSettings); // 用Content返回,指定Content-Type为json return Content(json, "application/json"); }
方案三:配置JsonResult的序列化参数
直接给JsonResult传递序列化设置,让它用正确的规则序列化对象:
[HttpPost] public JsonResult GetallData(int id) { MultipleViewModel model = new MultipleViewModel(); List<InformationSecurityData> iso = db.InformationSecurityDatas.Where(x => x.Supplier_ID == id).ToList(); List<SurveyForm> tender = db.SurveyForms.Where(x => x.Supplier_ID == id ).ToList(); List<ProcurementData> procurement = db.ProcurementDatas.Where(x => x.Supplier_ID == id ).ToList(); List<Supplier> supp = db.Suppliers.Where(x => x.Supplier_ID == id).ToList(); model.Inf_Sec_Dat = iso; model.Proc_Dat = procurement; model.Tender_Dat = tender; model.Supp_dat = supp; // 直接在JsonResult里指定序列化设置 return Json(model, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore }, JsonRequestBehavior.AllowGet); }
前端代码修正
你的前端代码里有个小问题:当返回正确的Json时,data已经是JavaScript对象了,不需要再用jQuery.parseJSON(data)解析,否则会导致错误。修改后的success函数:
success: function (data) { alert("success "); // data已经是解析后的对象,无需再次parse const Objdata = data; // 查看对象可以转成字符串 alert(JSON.stringify(Objdata)); if (Objdata.Inf_Sec_Dat) { const iso_data = []; // 建议用局部变量,避免全局污染 $.each(Objdata.Inf_Sec_Dat, function (i, item) { iso_data.push(item.Total_Score); }); alert(iso_data); bindChart(iso_data); } if (Objdata.Tender_Dat) { const tender_data = []; $.each(Objdata.Tender_Dat, function (i, item) { tender_data.push(item.Total_Score); }); bindChart2(tender_data); } },
内容的提问来源于stack exchange,提问作者kyr
相关产品推荐
相关产品推荐

