Razor Collection 绑定故障
Razor Collection binding malfunction
我在使用 ASP.NET Core 3.1 网站时遇到了一个奇怪的问题。
我使用 Razor 生成的网页,并绑定了来自 ViewModel class 的对象集合。它就像一个魅力,直到我从这个集合中删除这个对象之一。我可以看到对象已正确删除到控制器中,更新后的集合已发送到 Razor 引擎,并且 Razor 引擎将更新后的集合插入到网页中。
但是,最后,浏览器收到了一个不正确的集合,其中包含已删除的项目并且缺少集合中的最后一项,尽管这不是控制器发送的内容 . 某些东西 正在网页生成后修改此集合,我无法弄清楚是什么,我快要疯了。
浏览器的缓存被禁用(我仔细检查了收到的 HTML 是否与显示的 HTML 匹配),我没有任何定制的中间件 运行ning在 Razor 引擎之后,我没有任何客户端脚本,也没有 AJAX,控制器只有 运行 一次请求。
对于进一步的故障排除步骤,您有什么提示吗?我怎样才能深入 ASP 引擎找出这个 HTML 修改的地方?
详细步骤:
FooView
初始化为 4 个项目,Id 从 1 到 4,Names Foo1
, Foo2
, Foo3
, Foo4
- 客户点击
Foo2
删除按钮
FooController
处理请求,并更新现在包含 Id = {1,3,4}, Names={Foo1
, Foo3
, [=16= 的集合]}
FooController
将此集合发送到 Razor 引擎,通过插入断点,我可以评估插入了 Foo1、Foo3 和 Foo4,但没有插入 Foo2
- 当它返回到浏览器时,我在 table 中得到
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>
经过长时间的调查,我发现当生成 Razor 页面时,模型对象和 ViewData.ModelState 字典 中的数据之间存在差异我无法解释。 Model 对象包含更新的列表,而 ModelState 嵌入式字典包含旧的 key/value 对,引用提交的列表(未更新的列表)。
进行调试检查时,cshtml 文件@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);
}
}
我在使用 ASP.NET Core 3.1 网站时遇到了一个奇怪的问题。
我使用 Razor 生成的网页,并绑定了来自 ViewModel class 的对象集合。它就像一个魅力,直到我从这个集合中删除这个对象之一。我可以看到对象已正确删除到控制器中,更新后的集合已发送到 Razor 引擎,并且 Razor 引擎将更新后的集合插入到网页中。
但是,最后,浏览器收到了一个不正确的集合,其中包含已删除的项目并且缺少集合中的最后一项,尽管这不是控制器发送的内容 . 某些东西 正在网页生成后修改此集合,我无法弄清楚是什么,我快要疯了。
浏览器的缓存被禁用(我仔细检查了收到的 HTML 是否与显示的 HTML 匹配),我没有任何定制的中间件 运行ning在 Razor 引擎之后,我没有任何客户端脚本,也没有 AJAX,控制器只有 运行 一次请求。
对于进一步的故障排除步骤,您有什么提示吗?我怎样才能深入 ASP 引擎找出这个 HTML 修改的地方?
详细步骤:
FooView
初始化为 4 个项目,Id 从 1 到 4,NamesFoo1
,Foo2
,Foo3
,Foo4
- 客户点击
Foo2
删除按钮 FooController
处理请求,并更新现在包含 Id = {1,3,4}, Names={Foo1
,Foo3
, [=16= 的集合]}FooController
将此集合发送到 Razor 引擎,通过插入断点,我可以评估插入了 Foo1、Foo3 和 Foo4,但没有插入 Foo2- 当它返回到浏览器时,我在 table 中得到
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>
经过长时间的调查,我发现当生成 Razor 页面时,模型对象和 ViewData.ModelState 字典 中的数据之间存在差异我无法解释。 Model 对象包含更新的列表,而 ModelState 嵌入式字典包含旧的 key/value 对,引用提交的列表(未更新的列表)。
进行调试检查时,cshtml 文件@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);
}
}