You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET MVC中Json序列化循环引用与重复序列化问题求助

解决ASP.NET MVC返回Json时的循环引用与重复序列化问题

我来帮你搞定这个头疼的问题,这在使用EF的ASP.NET MVC项目里非常常见,咱们一步步拆解原因和解决方案:

错误原因分析

  1. 循环引用错误:你看到的DynamicProxies相关错误,是因为EF为了支持延迟加载生成了动态代理对象,这些对象里的导航属性(比如Supplier和InformationSecurityData互相引用)会导致序列化时出现循环引用,陷入死循环。
  2. 重复序列化问题:当你手动用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 10:08:45