Обнаружена циклическая ссылка при сериализации объекта типа при выполнении вызова ajax

На мой взгляд, я использую модель просмотра, и у меня есть форма, в которой есть только одно текстовое поле, которое принимает даты (не часть модели просмотра) и 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>
}

Я пытаюсь сделать, если пользователь выбирает дату и нажимает кнопку поиска. Я бы хотел, чтобы страница не обновлялась, а данные таблиц были изменены в зависимости от даты. На данный момент я получаю:

A circular reference was detected while serializing an object of type 'System.Data.Entity.DynamicProxies.tbl_WeighAssc_8AA7AB5F9DAB261D5142F1D5F5BA6705A588A5AAD2D369FBD4B4BC1BBE0487D4'.

Viewmodel

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.info("success");
            $("body").html(response);
        },
        error: function(jqXHR, textStatus, errorThrown) {
            console.info(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 actionresult не равны нулю, тогда он переходит в оператор else, который возвращает объект JSON. При отладке это происходит, и когда представление возвращается, я получаю сообщение об ошибке, которое я опубликовал выше.

Есть ли способ заменить модель в представлении тем, что я возвращаю из вызова ajax, чтобы таблицы могли основываться на правильной дате без обновления страницы?

Любая помощь приветствуется.

ОБНОВИТЬ

Основываясь на ответе ниже, я отредактировал оператор else в моем методе контроллера, чтобы:

Контроллер

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.info("success");
            console.info(response);
            $("body").html(response);
        },
        error: function(jqXHR, textStatus, errorThrown) {
            console.info(jqXHR);
        }
    });
});

Но теперь, когда выбрана дата, меня возвращают на страницу, которая показывает Json как обычный текстовый файл и теряет HTML и CSS, как в обычном представлении.

Вот что мне возвращают, когда выбрана дата и нажата кнопка.

Обнаружена циклическая ссылка при сериализации объекта типа при выполнении вызова ajax

Кроме того, когда я проверяю консоль, когда я выбираю дату и нажимаю кнопку для отправки этой даты на контроллер, я вижу следующее:

Обнаружена циклическая ссылка при сериализации объекта типа при выполнении вызова ajax

ОБНОВЛЕНИЕ 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>
Как сделать HTTP-запрос в Javascript?
Как сделать HTTP-запрос в Javascript?
В JavaScript вы можете сделать HTTP-запрос, используя объект XMLHttpRequest или более новый API fetch. Вот пример для обоих методов:
3
0
458
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Это сообщение об ошибке означает, что одно из ваших дочерних свойств ссылается на родительский объект, и сериализация JSON вызывает циклический цикл.

Чтобы исправить это, замените это:

return Json(person, JsonRequestBehavior.AllowGet);

с этим:

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

Вам нужно будет установить NewtonSoft.Json:

using Newtonsoft.Json;

Это избавляет от ошибки, но вместо этого теперь мне предлагается диалоговое окно Вы хотите открыть или сохранить xxxxxxxxxxxx.json (19,8 КБ) с localhost? вместо обновления таблиц с правильными данными.

Grizzly 13.09.2018 20:54

Вы описали поведение, потому что вы не анализируете и не обрабатываете возвращенный JSON в своем разделе ajax-success. Не зная, как выглядит ваша таблица, я не могу сказать, настроена ли ваша таблица на использование JSON в первую очередь. Я подозреваю, что вы использовали синтаксис RAZOR при начальной загрузке страницы, но последующие обновления, которые извлекают данные JSON, должны быть переданы обратно в вашу HTML-таблицу, чтобы она знала, что нужно обновить эти значения. Просто выполняю $ ("body"). Html (response); на самом деле не инструктирует вашу HTML-таблицу обновлять ее значение.

kots 15.09.2018 09:24

Я обновил свой вопрос, чтобы показать вам, как моя таблица выглядит в HTML / Razor

Grizzly 17.09.2018 15:04

Обнаружена циклическая ссылка при сериализации объекта типа произошло из-за того, что сериализатор JSON не поддерживает циклические ссылки внутри вашей иерархии объектов (т. Е. Передача PersonnelDetailsVm, содержащего ссылки на модели данных). Чтобы решить эту проблему, используйте JSON.NET JsonConvert.SerializeObject() со следующими настройками по умолчанию:

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

После этого вы можете вернуть JsonResult из модели просмотра:

string jsonStr = JsonConvert.SerializeObject(person);

return Json(jsonStr);

Если вы используете IE и сталкиваетесь с диалоговым окном сохранения из-за удобная конфигурация ошибок JSON, вам может потребоваться добавить 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);, потому что вызов AJAX должен оставаться на той же странице.

Я отредактировал свой код в соответствии с тем, что вы опубликовали, но теперь меня возвращают на страницу с JSON в виде простого текста ... Я потерял то, как выглядит мое представление. Я опубликовал обновление в своем вопросе

Grizzly 14.09.2018 14:22

Кроме того, когда я отлаживаю, все проходит через контроллер без исключений, но по какой-то причине мне возвращается ошибка 400, которая входит в часть error моего ajax?

Grizzly 14.09.2018 14:42

Настройка ReferenceLoopHandling = ReferenceLoopHandling.Ignore решит вашу проблему, связанную с исключением циклической ссылки.

Теперь о проблемах, которые вы представили в своих обновлениях, я думаю, у вас может быть некоторое недопонимание того, как работает запрос Ajax. Я думаю, это потому, что, когда вы делаете запрос ajax на сервер, он ответит данными 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>

Я надеюсь, это поможет вам!

У вас есть 2 разных метода возврата, и вы устанавливаете содержимое тела в ответ на запрос, который, если выполняется инструкция else, будет JSON, а не html.

Я бы посоветовал либо всегда возвращать JSON, либо всегда возвращать View / Partial.

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);
}
Ответ принят как подходящий

Насколько я могу судить по вашей проблеме, чтобы исправить ее, вы можете выполнить следующие действия:

1- Просмотр

Добавить частичное представление (_Detail.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.info("success");
            $("body").html(response);
        },
        error: function(jqXHR, textStatus, errorThrown) {
            console.info(jqXHR);
        }
    });
});

Таким образом, response представляет собой HTML-код, который исходит из частичного представления, и в нем есть все классы в том виде, в каком вы его спроектировали.

Я бы предложил следующие шаги

  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("");
    }

Логику ViewModel можно оставить как есть, вам нужно разделить представления. Позвольте мне знать, если это помогает...

Вам нужно создать два метода, первый для возврата представления с типом возвращаемого значения ActionResult:

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

И второй метод, который будет вызываться через Ajax для возврата данных Json с типом JsonResult.

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

Чтобы предотвратить повторение одной и той же логики получения данных дважды, вы можете переместить всю логику данных в метод Json и сохранить возврат метода View без данных, а затем просто запустить вызов Ajax, когда загрузка страницы завершена, чтобы получить начальные данные из метода Json.

Другие вопросы по теме