代码之家  ›  专栏  ›  技术社区  ›  Grizzly

在执行ajax调用时序列化类型的对象时检测到循环引用

  •  3
  • Grizzly  · 技术社区  · 6 年前

    在我的视图中,我使用的是Viewmodel,并且我有一个窗体,它只有一个接受日期的文本框(不是Viewmodel的一部分)和3个表。默认情况下,在页面加载时。。表中填充了基于今天日期的数据(您可以在下面的控制器代码中看到),但是如果用户选择了一个日期并单击了搜索按钮,那么我希望表中的数据在没有基于他们选择的日期进行页面刷新的情况下被更改。

    @using (Html.BeginForm())
    {
        <div class="form-group mb-3 mt-3" style="margin-right: -1.3%;">
            <div class="input-group col-md-3 offset-md-9">
                @Html.TextBox("detailsDate", null, new { id = "Details-Date", @class = "form-control datetimepicker" })
                <div class="input-group-append">
                    <button id="Details-Date-Btn" type="submit" class="btn btn-outline-primary"><span class="fa fa-search"></span></button>
                </div>
            </div>
        </div>
    }
    

    我要做的是,如果用户选择和日期,并点击搜索按钮。。我想页面不刷新,表数据已根据日期更改。从现在起,我得到:

    序列化类型为“”的对象时检测到循环引用System.Data.Entity.DynamicProxies.tbl_WeighAssc_8AA7AB5F9DAB261D5142F1D5F5BA6705A588A5AAD2D369FBD4B4BC1BBE0487D4'.

    public class PersonnelDetailsVm
    {
        private static ConnectionString db = new ConnectionString();
        public PersonnelDetailsVm()
        {
            CurrentWeekDates = new List<DateTime>();
            WeighAssociations = new List<tbl_WeighAssc>();
            ArrestAssociations = new List<tbl_TEUArrestAssc>();
            InspectionAssociations = new List<tblTEUInspectionAssc>();
        }
        public string IBM { get; set; }
    
        [Display(Name = "Name")]
        public string UserName { get; set; }
    
        public bool Active { get; set; }
    
        public List<DateTime> CurrentWeekDates { get; set; }
        public List<tbl_WeighAssc> WeighAssociations { get; set; }
        public List<tbl_TEUArrestAssc> ArrestAssociations { get; set; }
        public List<tblTEUInspectionAssc> InspectionAssociations { get; set; }
        public List<code_WeighLocation> WeighLocations => db.code_WeighLocation.ToList();
        public List<code_ArrestType> ArrestTypes => db.code_ArrestType.ToList();
        public List<code_InspectionLevel> InspectionLevels => db.code_InspectionLevel.ToList();
    }
    

    // Submission
    //var redirectUrl = '@Url.Action("Index", "Personnels")';
    var settings = {};
    settings.baseUri = '@Request.ApplicationPath';
    var infoGetUrl = "";
    if (settings.baseUri === "/AppName") {
        infoGetUrl = settings.baseUri + "/Personnels/Details/";
    } else {
        infoGetUrl = settings.baseUri + "Personnels/Details/";
    }
    
    $("#Details-Date-Btn").click(function() {
        $.ajax({
            url: infoGetUrl,
            method: "POST",
            data: $("form").serialize(),
            success: function(response) {
                console.log("success");
                $("body").html(response);
            },
            error: function(jqXHR, textStatus, errorThrown) {
                console.log(jqXHR);
            }
        });
    });
    

    控制器:

    public ActionResult Details(string id, string detailsDate)
    {
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
    
        tblPersonnel tblPersonnel = db.tblPersonnels.Find(id);
    
        if (tblPersonnel == null)
        {
            return HttpNotFound();
        }
    
        Mapper.Initialize(config => config.CreateMap<tblPersonnel, PersonnelDetailsVm>());
        PersonnelDetailsVm person = Mapper.Map<tblPersonnel, PersonnelDetailsVm>(tblPersonnel);
    
        var employeeData = EmployeeData.GetEmployee(person.IBM);
    
        person.UserName =
            $"{ConvertRankAbbr.Conversion(employeeData.Rank_Position)} {employeeData.FirstName} {employeeData.LastName}";
    
        if (string.IsNullOrWhiteSpace(detailsDate))
        {
            var startOfWeek = DateTime.Today.AddDays((int)CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek -
                                                     (int)DateTime.Today.DayOfWeek);
            person.CurrentWeekDates = Enumerable.Range(0, 7).Select(i => startOfWeek.AddDays(i)).ToList();
            var teuFormIds = db.tbl_TEUForm
                .Where(x => person.CurrentWeekDates.Contains(x.EventDate) && x.PersonnelIBM == person.IBM).Select(t => t.Id).ToList();
    
            person.WeighAssociations = db.tbl_WeighAssc.Where(x => teuFormIds.Contains(x.TEUId)).ToList();
            person.ArrestAssociations = db.tbl_TEUArrestAssc.Where(x => teuFormIds.Contains(x.TEUId)).ToList();
            person.InspectionAssociations =
                db.tblTEUInspectionAsscs.Where(x => teuFormIds.Contains(x.TEUId)).ToList();
    
    
            return View(person);
    
        }
        else
        {
            var paramDate = DateTime.ParseExact(detailsDate, "MM/dd/yyyy", CultureInfo.CurrentCulture);
    
            var startOfWeek = paramDate.AddDays((int)CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek -
                                                     (int)paramDate.DayOfWeek);
            person.CurrentWeekDates = Enumerable.Range(0, 7).Select(i => startOfWeek.AddDays(i)).ToList();
            var teuFormIds = db.tbl_TEUForm
                .Where(x => person.CurrentWeekDates.Contains(x.EventDate) && x.PersonnelIBM == person.IBM).Select(t => t.Id).ToList();
    
            person.WeighAssociations = db.tbl_WeighAssc.Where(x => teuFormIds.Contains(x.TEUId)).ToList();
            person.ArrestAssociations = db.tbl_TEUArrestAssc.Where(x => teuFormIds.Contains(x.TEUId)).ToList();
            person.InspectionAssociations =
                db.tblTEUInspectionAsscs.Where(x => teuFormIds.Contains(x.TEUId)).ToList();
    
            return Json(person, JsonRequestBehavior.AllowGet);
        }
    
    }
    

    detailsDate 不为null,则进入 else 返回JSON对象的语句。当调试完成并且返回视图时,我收到了上面发布的错误。

    有没有办法用我从ajax调用返回的内容替换视图中的模型,这样表就可以基于正确的日期而不需要刷新页面?

    非常感谢您的帮助。

    更新

    其他的 我的控制器方法中的语句:

    控制器

    else
    {
        var paramDate = DateTime.ParseExact(detailsDate, "MM/dd/yyyy", CultureInfo.CurrentCulture);
    
        var startOfWeek = paramDate.AddDays((int)CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek -
                                                 (int)paramDate.DayOfWeek);
        person.CurrentWeekDates = Enumerable.Range(0, 7).Select(i => startOfWeek.AddDays(i)).ToList();
        var teuFormIds = db.tbl_TEUForm
            .Where(x => person.CurrentWeekDates.Contains(x.EventDate) && x.PersonnelIBM == person.IBM).Select(t => t.Id).ToList();
    
        person.WeighAssociations = db.tbl_WeighAssc.Where(x => teuFormIds.Contains(x.TEUId)).ToList();
        person.ArrestAssociations = db.tbl_TEUArrestAssc.Where(x => teuFormIds.Contains(x.TEUId)).ToList();
        person.InspectionAssociations =
            db.tblTEUInspectionAsscs.Where(x => teuFormIds.Contains(x.TEUId)).ToList();
    
        JsonConvert.DefaultSettings = () => new JsonSerializerSettings()
        {
            PreserveReferencesHandling = PreserveReferencesHandling.All,
            ReferenceLoopHandling = ReferenceLoopHandling.Ignore
        };
    
        var jsonStr = JsonConvert.SerializeObject(person);
    
        return Json(jsonStr, "text/plain");
    }
    

    我的jQuery/Ajax仍然是一样的:

    $("#Details-Date-Btn").click(function() {
        $.ajax({
            url: infoGetUrl,
            data: $("form").serialize(),
            success: function(response) {
                console.log("success");
                console.log(response);
                $("body").html(response);
            },
            error: function(jqXHR, textStatus, errorThrown) {
                console.log(jqXHR);
            }
        });
    });
    

    但是现在,当日期被选中时,我将返回到一个页面,该页面像纯文本文件一样显示Json,像普通视图一样丢失HTML和CSS。

    这是我被返回时,一个日期被选中,并点击按钮。

    enter image description here

    另外,当我检查控制台时,当我选择一个日期并单击该日期发送到控制器的按钮时,我看到:

    enter image description here

    更新2

    这是我的一张桌子。。其他的都是相同的设置:

    <table class="table table-bordered">
        <thead>
            <tr>
                <th></th>
                @foreach (var date in Model.CurrentWeekDates)
                {
                    <th class="text-center">@date.ToString("ddd") <br /> @date.ToShortDateString()</th>
                }
                    <th class="text-center table-success">Total For Week</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var weighLocation in Model.WeighLocations)
            {
                <tr class="text-center">
                    <td class="table-dark">@weighLocation.Weigh_Location</td>
                    @foreach (var date in Model.CurrentWeekDates)
                    {
                        if (Model.WeighAssociations.Any(x => x.tbl_TEUForm.EventDate == date && x.WeighLocationId == weighLocation.ID))
                        {
                            <td>@Model.WeighAssociations.Single(x => x.tbl_TEUForm.EventDate == date && x.WeighLocationId == weighLocation.ID).OccurenceCount</td>
                        }
                        else
                        {
                            <td>0</td>
                        }
    
                    }
                    <td class="table-success font-weight-bold">@Model.WeighAssociations.Where(x => x.WeighLocationId == weighLocation.ID).Sum(x => x.OccurenceCount)</td>
                </tr>
            }
        </tbody>
    </table>
    
    7 回复  |  直到 6 年前
        1
  •  3
  •   Ali Soltani    6 年前

    1-视图

    添加局部视图(_细节.cshtml)

    你需要一个 partial view 喜欢 _Detail table 这样地:

    @model PersonnelDetailsVm  
    
    <table class="table table-bordered">
        <thead>
            <tr>
                <th></th>
                @foreach (var date in Model.CurrentWeekDates)
                {
                    <th class="text-center">@date.ToString("ddd") <br /> @date.ToShortDateString()</th>
                }
                    <th class="text-center table-success">Total For Week</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var weighLocation in Model.WeighLocations)
            {
                <tr class="text-center">
                    <td class="table-dark">@weighLocation.Weigh_Location</td>
                    @foreach (var date in Model.CurrentWeekDates)
                    {
                        if (Model.WeighAssociations.Any(x => x.tbl_TEUForm.EventDate == date && x.WeighLocationId == weighLocation.ID))
                        {
                            <td>@Model.WeighAssociations.Single(x => x.tbl_TEUForm.EventDate == date && x.WeighLocationId == weighLocation.ID).OccurenceCount</td>
                        }
                        else
                        {
                            <td>0</td>
                        }
    
                    }
                    <td class="table-success font-weight-bold">@Model.WeighAssociations.Where(x => x.WeighLocationId == weighLocation.ID).Sum(x => x.OccurenceCount)</td>
                </tr>
            }
        </tbody>
    </table>
    

    2-控制器

    public ActionResult Details(string id, string detailsDate)
    {
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
    
        tblPersonnel tblPersonnel = db.tblPersonnels.Find(id);
    
        if (tblPersonnel == null)
        {
            return HttpNotFound();
        }
    
        Mapper.Initialize(config => config.CreateMap<tblPersonnel, PersonnelDetailsVm>());
        PersonnelDetailsVm person = Mapper.Map<tblPersonnel, PersonnelDetailsVm>(tblPersonnel);
    
        var employeeData = EmployeeData.GetEmployee(person.IBM);
    
        person.UserName =
            $"{ConvertRankAbbr.Conversion(employeeData.Rank_Position)} {employeeData.FirstName} {employeeData.LastName}";
    
        if (string.IsNullOrWhiteSpace(detailsDate))
        {
            var startOfWeek = DateTime.Today.AddDays((int)CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek -
                                                     (int)DateTime.Today.DayOfWeek);
            person.CurrentWeekDates = Enumerable.Range(0, 7).Select(i => startOfWeek.AddDays(i)).ToList();
            var teuFormIds = db.tbl_TEUForm
                .Where(x => person.CurrentWeekDates.Contains(x.EventDate) && x.PersonnelIBM == person.IBM).Select(t => t.Id).ToList();
    
            person.WeighAssociations = db.tbl_WeighAssc.Where(x => teuFormIds.Contains(x.TEUId)).ToList();
            person.ArrestAssociations = db.tbl_TEUArrestAssc.Where(x => teuFormIds.Contains(x.TEUId)).ToList();
            person.InspectionAssociations =
                db.tblTEUInspectionAsscs.Where(x => teuFormIds.Contains(x.TEUId)).ToList();
    
    
            // return View(person); 
    
    
    
        }
        else
        {
            var paramDate = DateTime.ParseExact(detailsDate, "MM/dd/yyyy", CultureInfo.CurrentCulture);
    
            var startOfWeek = paramDate.AddDays((int)CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek -
                                                     (int)paramDate.DayOfWeek);
            person.CurrentWeekDates = Enumerable.Range(0, 7).Select(i => startOfWeek.AddDays(i)).ToList();
            var teuFormIds = db.tbl_TEUForm
                .Where(x => person.CurrentWeekDates.Contains(x.EventDate) && x.PersonnelIBM == person.IBM).Select(t => t.Id).ToList();
    
            person.WeighAssociations = db.tbl_WeighAssc.Where(x => teuFormIds.Contains(x.TEUId)).ToList();
            person.ArrestAssociations = db.tbl_TEUArrestAssc.Where(x => teuFormIds.Contains(x.TEUId)).ToList();
            person.InspectionAssociations =
                db.tblTEUInspectionAsscs.Where(x => teuFormIds.Contains(x.TEUId)).ToList();
    
            // return Json(person, JsonRequestBehavior.AllowGet);
        }
    
        // return PartialView with the person model
        return PartialView("_Detail", person);
    
    }
    

    // return View(person); 
    // return Json(person, JsonRequestBehavior.AllowGet);
    

    3-Ajax调用

    获取局部视图并按其填充表单

    您不需要对ajax调用进行任何更改,可以这样做:

    $("#Details-Date-Btn").click(function() {
        $.ajax({
            url: infoGetUrl,
            method: "POST",
            data: $("form").serialize(),
            success: function(response) {
                console.log("success");
                $("body").html(response);
            },
            error: function(jqXHR, textStatus, errorThrown) {
                console.log(jqXHR);
            }
        });
    });
    

    response 这样一个html来自于局部视图,它包含了您设计的所有类。

        2
  •  1
  •   kots    6 年前

    若要修复,请替换此项:

    return Json(person, JsonRequestBehavior.AllowGet);
    

    return Content(JsonConvert.SerializeObject(person,
                    new JsonSerializerSettings
                    {
                        ReferenceLoopHandling = ReferenceLoopHandling.Ignore
                    }), "application/json");
    

    您必须安装NewtonSoft.Json:

    using Newtonsoft.Json;
    
        3
  •  1
  •   Tetsuya Yamamoto    6 年前

    序列化类型的对象时检测到循环引用 PersonnelDetailsVm 包含对数据模型的引用)。要解决此问题,请使用JSON.NET的 JsonConvert.SerializeObject() 默认设置如下:

    JsonConvert.DefaultSettings = () => new JsonSerializerSettings
    {
        PreserveReferencesHandling = PreserveReferencesHandling.All,
        ReferenceLoopHandling = ReferenceLoopHandling.Ignore
    };
    

    之后,你可以回来 JsonResult 从viewmodel:

    string jsonStr = JsonConvert.SerializeObject(person);
    
    return Json(jsonStr);
    

    如果您使用IE时遇到保存对话框,因为 friendly JSON errors configuration text/html text/plain 返回JSON数据时:

    return Json(jsonStr, "text/html");
    

    Json() 控制器类中的方法如下:

    protected new JsonResult Json(object data)
    {
        if (!Request.AcceptTypes.Contains("application/json"))
            return base.Json(data, "text/plain");
        else
            return base.Json(data);
    }
    

    另外 return View(person); 你可以考虑 return PartialView("Details", person);

        4
  •  1
  •   Dipen Shah    6 年前

    ReferenceLoopHandling = ReferenceLoopHandling.Ignore 将处理与循环引用异常相关的问题。

    关于您在更新中提出的问题,我认为您可能对Ajax请求的工作方式有一些误解。我认为这是因为当您向服务器发出ajax请求时,它将用JSON数据进行响应,JSON数据将表示您的视图模型和模型 对您的视图(cshtml)代码是不可知的 ,所以当你打电话的时候 $("body").html(response); 您正在用JSON视图模型的字符串化表示替换页面内容。这里需要说明的是,当您发出ajax请求时,只有后端代码会被执行,而视图代码(cshtml)不会被执行。

    要解决此问题,您必须替换表本身的内容,而不是页面主体的内容,因此Ajax成功回调应该类似于:

    var tempData = {
    "IBM": "IBM",
    "UserName": "UserName",
    "Active": false,
    "CurrentWeekDates": [], 
    "WeighAssociations": [],
    "ArrestAssociations": [],
    "InspectionAssociations": [],
    "WeighLocations": [],
    "ArrestTypes": [],
    "InspectionLevels": []
    };
    
    function onSuccess(response){
    	var table = $("#tblData");
      table.html("");
      
      // code to create your head same code as your cshtml
    	table.append("<thead><th>New Column</th></thead>");
      table.append("<tr><td>Column 1</td></tr>");
      
      $("#btnLoad").text("Loaded");
    }
    
    $("#btnLoad").click(function(){
      $("#btnLoad").attr("disabled", "");
      $("#btnLoad").text("Loading...");
      // call onSuccess function after 5 second to replicate server call
      setTimeout(function(){ onSuccess(tempData) }, 5000);
    });
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    
    <button id="btnLoad">Load Data</button>
    <table id="tblData" class="table table-bordered">
        <thead>
            <tr>
                <th></th>
                <th class="text-center">Mon<br /> 01-01-1990</th>
                <th class="text-center table-success">Total For Week</th>
            </tr>
        </thead>
        <tbody>
          <tr class="text-center">
            <td class="table-dark">Column 1</td>
            <td>Columns 2</td>
            <td>0</td>
            <td class="table-success font-weight-bold">0</td>
          </tr>
        </tbody>
    </table>

    我希望这对你有帮助!

        5
  •  0
  •   Mark F    6 年前

    您有两种不同的返回方法,您将主体内容设置为请求的响应,如果 else 运行的语句将是JSON而不是html。

    else
    {
    var paramDate = DateTime.ParseExact(detailsDate, "MM/dd/yyyy", CultureInfo.CurrentCulture);
    
    var startOfWeek = paramDate.AddDays((int)CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek -
                                             (int)paramDate.DayOfWeek);
    person.CurrentWeekDates = Enumerable.Range(0, 7).Select(i => startOfWeek.AddDays(i)).ToList();
    var teuFormIds = db.tbl_TEUForm
        .Where(x => person.CurrentWeekDates.Contains(x.EventDate) && x.PersonnelIBM == person.IBM).Select(t => t.Id).ToList();
    
    person.WeighAssociations = db.tbl_WeighAssc.Where(x => teuFormIds.Contains(x.TEUId)).ToList();
    person.ArrestAssociations = db.tbl_TEUArrestAssc.Where(x => teuFormIds.Contains(x.TEUId)).ToList();
    person.InspectionAssociations =
        db.tblTEUInspectionAsscs.Where(x => teuFormIds.Contains(x.TEUId)).ToList();
    
    JsonConvert.DefaultSettings = () => new JsonSerializerSettings()
    {
        PreserveReferencesHandling = PreserveReferencesHandling.All,
        ReferenceLoopHandling = ReferenceLoopHandling.Ignore
    };
    
    var jsonStr = JsonConvert.SerializeObject(person);
    
    //return Json(jsonStr, "text/plain");
    return Partial(person);
    }
    
        6
  •  0
  •   Vikas Sharma    6 年前

    我建议采取以下步骤

    1. 一个过滤器的局部视图,包括DateTime和Submit按钮(FilterPartial)
    2. 要呈现的表的一个部分视图(ResultsPartial)

    当主体被加载时,然后加载第一个部分视图(我们称之为FilterPartial),它将设置ResultsPartial视图中的值。

    function GetData(params) {
    $.ajax({
        type: "POST",
        url: '/controller/Action',
        data: {
            //Parameters
        },
        dataType: 'html',
        success: function (data) {
            //You can either load the html directly or render the control here 
        }
    });
    

      public PartialViewResult Action()
        {
           return PartialView("");
        }
    

    让我知道如果这有帮助。。。

        7
  •  0
  •   LazZiya    6 年前

    您需要创建两个方法,第一个方法返回ActionResult返回类型的视图:

    public ActionResult Details(string id, string detailsDate)
    {
    ....
    return View(person);
    }
    

    第二个方法将通过Ajax调用,以返回JsonResult类型的Json数据

    public JsonResult GetData(string id, string detailsDate)
    {
    ....
    return Json(person, JsonRequestBehavior.AllowGet);
       }
    

    为了防止重复相同的获取数据逻辑两次,您可以将所有数据逻辑移到Json方法,并保持View方法返回时没有数据,然后在页面加载完成时触发Ajax调用,从Json方法获取初始数据。