Неисправность привязки Razor Collection - PullRequest
0 голосов
/ 30 марта 2020

У меня странная проблема с ASP. NET Core 3.1.

Я использую сгенерированные Razor веб-страницы и связываю коллекцию объектов из класса ViewModel. Это работает как брелок, пока я не удалю один из этих объектов из этой коллекции. Я вижу, что объект правильно удален в контроллере, что обновленная коллекция отправляется в Razor Engine, и что Razor Engine вставляет обновленную коллекцию в веб-страницу.

Но, в конце концов, браузер получает неверную коллекцию, содержащую удаленный элемент и пропускающую последний элемент из коллекции, , несмотря на то, что контроллер не отправил . Что-то модифицирует эту коллекцию после генерации веб-страницы, и я не могу понять, что, я схожу с ума.

Кэш браузера отключен (и я дважды проверил, что полученный HTML соответствует отображаемому HTML), у меня нет никакого специального промежуточного программного обеспечения, работающего после Razor Engine, я не У него нет ни скрипта на стороне клиента, ни AJAX, а контроллер запускается только один раз по запросу.

Не могли бы вы подсказать какие-либо дальнейшие действия по устранению неполадок? Как я могу погрузиться в ASP Engine, чтобы выяснить, где это HTML изменено?

Подробные шаги:

  • FooView инициализируется с 4 пунктами, Id от 1 4, имена Foo1, Foo2, Foo3, Foo4
  • Клиент нажимает Foo2 Кнопка удаления
  • FooController обрабатывает запросы и обновляет коллекцию который теперь содержит Id = {1,3,4}, Names = {Foo1, Foo3, Foo4}
  • FooController отправляет эту коллекцию в Razor Engine, вставляя точку останова Я могу оценить, что Foo1, Foo3 и Foo4 вставлены, но нет Foo2
  • Когда дело доходит до браузера, я получаю Foo1, Foo2 и Foo3 в таблице. Foo4 отсутствует.
public class FooVM
{
    public int Id { get; set; }
    public string Name { get; set; }

}

public class MasterViewModel
{
    public string OtherProperty1 { get; set; }
    public string OtherProperty2 { get; set; }

    private List<FooVM> Foos { get; set; }

}

public class FooController : Controller
{
    [HttpPost("Delete")]
    public IActionResult DeletePOST(MasterViewModel model, string deleteId) {
        if (int.TryParse(deleteId, out int id) && model.Foos.Any(x => x.Id == id)) {
                model.Foos.Remove(model.Foos.First(x => x.Id == id));
            }
            return View("FooView", model);
    }
}
<!-- language: html -->

//FooView.cshtml File Extract
@model MasterViewModel
<form asp-controller="FooController " asp-action="UpdatePOST" method="post" id="detailedform">
<table>
    <tbody>
        @for (int i = 0; i < Model.Foos.Count; i++) {

            <td nowrap="nowrap">
                <input asp-for="@Model.Foos[i].Id"  readonly/>
            </td>

            <td nowrap="nowrap">
                <input asp-for="@Model.Foos[i].Name" />
            </td>

            <td nowrap="nowrap" class="text-center">
                <button type="submit" asp-action="DeletePOST" name="deleteId" value="@Model.Foos[i].Id" style="background-color:transparent; border:none">
                    <i class="fa fa-times fa-2x" style="color:red"></i>
                </button>
            </td>
            </tr>
        }

</tbody>
</table>
</form>



1 Ответ

0 голосов
/ 30 марта 2020

После долгого исследования я выяснил, что при создании страницы Razor было несоответствие между данными в объекте Model и словаре ViewData.ModelState , которые я не могу объяснить. Объект Model содержал обновленный список, тогда как встроенный словарь ModelState содержал старые пары ключ / значение, ссылаясь на представленный список (не обновленный).

При выполнении проверки отладки переменная cs html file @ Model.Foos [i] .Name показывает правильное значение, но похоже, что значение, вычисленное позже, используется для генерации окончательного HTML, взято из ModelState, который не соответствует.

Это ошибка?

В любом случае, я решил проблему, добавив ModelState.Clear () в контроллер, прежде чем генерировать представление.

public class FooController : Controller
{
    [HttpPost("Delete")]
    public IActionResult DeletePOST(MasterViewModel model, string deleteId) {
        if (int.TryParse(deleteId, out int id) && model.Foos.Any(x => x.Id == id)) {
                model.Foos.Remove(model.Foos.First(x => x.Id == id));
            }
            ModelState.Clear();
            return View("FooView", model);
    }
}
...