当我从具有多个表单的视图提交表单时,为什么我的控制器会收到空值?使用 ASP.NET Core 5 MVC
Why do I receive null values in my controller when I submit a form from a view with multiple forms? With ASP.NET Core 5 MVC
我正在使用 ASP.NET Core 5 MVC 开发 Web 应用程序,在其中我试图从接收 IEnumerable
(来自一个名为 Result
的模型),我用它动态填充每个表单的输入值。
但是,当我通过控制器从视图发送这些表单之一时,在控制器中我只从模型接收到一个对象,其中包含所有 null 或空值,这告诉我这个数据似乎是从未通过表格发送到我的控制器。
是否有更好的方法来完成此操作,或者如何将这些值从多个表单传递到我的控制器?如果我所做的已经完全错误,请提前道歉,我已经学习 ASP.NET Core MVC 几天了。
注意事项
我想要实现的是,用户可以在同一视图中输入属于同一模型的多个值,因为每个表单虽然相同,但都试图更新同一模型中的不同记录或列,或者table,所以当表单的提交发送到控制器时,视图不会改变,只有数据库中的记录随着视图中的每次提交而更新。如果有更好的方法或正确的方法来做到这一点,我愿意改变逻辑,因为正如我提到的,我使用框架的时间很少。
解释了问题和我的目标,我将更详细地解释提到的流程和代码:
从我的控制器的 Mechanical
方法中,我 return 对象列表到它们相应的视图,它们由 DataBaseContext
:
// CONTROLLER() that passes an enumerable list of Objects to View Mechanical.cshtml
public IActionResult Mechanical()
{
IEnumerable<Result> objList = _db.Results;
return View(objList);
}
在 Mechanical()
视图中,我得到了这个对象列表并通过 forEach()
循环对其进行迭代,其中我为每个对象创建了一个指向相同的控制器方法称为 Update()
,我在其中获取 null 和空对象的值(这是我的问题):
// VIEW
@model IEnumerable<FatForm.Models.Result>
@if (Model.Count() > 0)
{
@foreach(var result in Model)
{
<form method="post" asp-action="Update">
<input asp-for="@result.Id" hidden />
<input asp-for="@result.Type" hidden />
<input asp-for="@result.FatId" hidden />
<div class="border p-3">
<div class="form-group row">
<h2 class="text-black-50 pl-3">Edit Result</h2>
</div>
<div class="row">
<div class="col-12">
<div class="form-group row">
<div class="col-3">
<label asp-for="@result.Section"></label>
</div>
<div class="col-3">
<label asp-for="@result.Procedure"></label>
</div>
<div class="col-3">
<label asp-for="@result.ResultDescription"></label>
</div>
<div class="col-3">
<label asp-for="@result.Passed"></label>
</div>
</div>
<div class="form-group row">
<div class="col-3">
<input asp-for="@result.Section" class="form-control" />
</div>
<div class="col-3">
<input asp-for="@result.Procedure" class="form-control" />
</div>
<div class="col-3">
<input asp-for="@result.ResultDescription" class="form-control" />
<span asp-validation-for="@result.ResultDescription" class="text-danger"></span>
</div>
<div class="col-3">
<input asp-for="@result.Passed" class="form-control" />
<span asp-validation-for="@result.Passed" class="text-danger"></span>
</div>
</div>
<div class="form-group row">
<div class="col-8 offset-2 row">
<div class="col">
<input type="submit" class="btn btn-info w-75" value="Save" />
</div>
</div>
</div>
</div>
</div>
</div>
</form>
}
}
else
{
<p>No results created yet</p>
}
@section Scripts{
@{
<partial name="_ValidationScriptsPartial" />
}
}
我应该将表单值发送到以下 Update()
控制器方法,在该方法中我将所有对象值设为空:
// POST Update
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Update(Result obj)
{
if (ModelState.IsValid)
{
_db.Results.Update(obj);
_db.SaveChanges();
//return RedirectToAction("Index");
}
return View(obj);
}
正如我在开头所解释的,我希望能帮助我指出我做错了什么或我应该以什么方式做错。预先感谢您的帮助。
这里需要在你的action方法参数中添加FromBody属性
public IActionResult Update([FromBody]Result obj)
{
.....
}
模型绑定在源中查找名称模式 prefix.property_name
。如果没有找到,它只查找 property_name
而没有 prefix.In 你的代码,asp-for
标签助手将生成如下名称:result.propertyName
。它无法与后端匹配模型。您需要使用 [Bind(Prefix ="result")]
指定前缀:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Update([Bind(Prefix ="result")]Result obj)
{
//do your stuff...
}
至于在操作中接收 IEnumerable
参数,首先您需要更改剃刀视图以将表单移到 foreach 循环之外,然后您需要将 asp-for 标签助手属性更改为 @Model.ToList()[index].PropertyName
:
@model IEnumerable<Result>
@if (Model.Count() > 0)
{
<form method="post" asp-action="Update">
@for (int i = 0; i < Model.Count(); i++)
{
<input asp-for="@Model.ToList()[i].Id" hidden />
<input asp-for="@Model.ToList()[i].Type" hidden />
<input asp-for="@Model.ToList()[i].FatId" hidden />
<div class="border p-3">
<div class="form-group row">
<h2 class="text-black-50 pl-3">Edit Result</h2>
</div>
<div class="row">
<div class="col-12">
<div class="form-group row">
<div class="col-3">
<label asp-for="@Model.ToList()[i].Section"></label>
</div>
<div class="col-3">
<label asp-for="@Model.ToList()[i].Procedure"></label>
</div>
<div class="col-3">
<label asp-for="@Model.ToList()[i].ResultDescription"></label>
</div>
<div class="col-3">
<label asp-for="@Model.ToList()[i].Passed"></label>
</div>
</div>
<div class="form-group row">
<div class="col-3">
<input asp-for="@Model.ToList()[i].Section" class="form-control" />
</div>
<div class="col-3">
<input asp-for="@Model.ToList()[i].Procedure" class="form-control" />
</div>
<div class="col-3">
<input asp-for="@Model.ToList()[i].ResultDescription" class="form-control" />
<span asp-validation-for="@Model.ToList()[i].ResultDescription" class="text-danger"></span>
</div>
<div class="col-3">
<input asp-for="@Model.ToList()[i].Passed" class="form-control" />
<span asp-validation-for="@Model.ToList()[i].Passed" class="text-danger"></span>
</div>
</div>
</div>
</div>
</div>
}
<div class="form-group row">
<div class="col-8 offset-2 row">
<div class="col">
<input type="submit" class="btn btn-info w-75" value="Save" />
</div>
</div>
</div>
</form>
}
else
{
<p>No results created yet</p>
}
控制器:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Update(IEnumerable<Result> obj)
{
return View("Mechanical", obj);
}
结果:
我正在使用 ASP.NET Core 5 MVC 开发 Web 应用程序,在其中我试图从接收 IEnumerable
(来自一个名为 Result
的模型),我用它动态填充每个表单的输入值。
但是,当我通过控制器从视图发送这些表单之一时,在控制器中我只从模型接收到一个对象,其中包含所有 null 或空值,这告诉我这个数据似乎是从未通过表格发送到我的控制器。
是否有更好的方法来完成此操作,或者如何将这些值从多个表单传递到我的控制器?如果我所做的已经完全错误,请提前道歉,我已经学习 ASP.NET Core MVC 几天了。
注意事项
我想要实现的是,用户可以在同一视图中输入属于同一模型的多个值,因为每个表单虽然相同,但都试图更新同一模型中的不同记录或列,或者table,所以当表单的提交发送到控制器时,视图不会改变,只有数据库中的记录随着视图中的每次提交而更新。如果有更好的方法或正确的方法来做到这一点,我愿意改变逻辑,因为正如我提到的,我使用框架的时间很少。
解释了问题和我的目标,我将更详细地解释提到的流程和代码:
从我的控制器的
Mechanical
方法中,我 return 对象列表到它们相应的视图,它们由DataBaseContext
:// CONTROLLER() that passes an enumerable list of Objects to View Mechanical.cshtml public IActionResult Mechanical() { IEnumerable<Result> objList = _db.Results; return View(objList); }
在
Mechanical()
视图中,我得到了这个对象列表并通过forEach()
循环对其进行迭代,其中我为每个对象创建了一个指向相同的控制器方法称为Update()
,我在其中获取 null 和空对象的值(这是我的问题):
// VIEW
@model IEnumerable<FatForm.Models.Result>
@if (Model.Count() > 0)
{
@foreach(var result in Model)
{
<form method="post" asp-action="Update">
<input asp-for="@result.Id" hidden />
<input asp-for="@result.Type" hidden />
<input asp-for="@result.FatId" hidden />
<div class="border p-3">
<div class="form-group row">
<h2 class="text-black-50 pl-3">Edit Result</h2>
</div>
<div class="row">
<div class="col-12">
<div class="form-group row">
<div class="col-3">
<label asp-for="@result.Section"></label>
</div>
<div class="col-3">
<label asp-for="@result.Procedure"></label>
</div>
<div class="col-3">
<label asp-for="@result.ResultDescription"></label>
</div>
<div class="col-3">
<label asp-for="@result.Passed"></label>
</div>
</div>
<div class="form-group row">
<div class="col-3">
<input asp-for="@result.Section" class="form-control" />
</div>
<div class="col-3">
<input asp-for="@result.Procedure" class="form-control" />
</div>
<div class="col-3">
<input asp-for="@result.ResultDescription" class="form-control" />
<span asp-validation-for="@result.ResultDescription" class="text-danger"></span>
</div>
<div class="col-3">
<input asp-for="@result.Passed" class="form-control" />
<span asp-validation-for="@result.Passed" class="text-danger"></span>
</div>
</div>
<div class="form-group row">
<div class="col-8 offset-2 row">
<div class="col">
<input type="submit" class="btn btn-info w-75" value="Save" />
</div>
</div>
</div>
</div>
</div>
</div>
</form>
}
}
else
{
<p>No results created yet</p>
}
@section Scripts{
@{
<partial name="_ValidationScriptsPartial" />
}
}
我应该将表单值发送到以下
Update()
控制器方法,在该方法中我将所有对象值设为空:// POST Update [HttpPost] [ValidateAntiForgeryToken] public IActionResult Update(Result obj) { if (ModelState.IsValid) { _db.Results.Update(obj); _db.SaveChanges(); //return RedirectToAction("Index"); } return View(obj); }
正如我在开头所解释的,我希望能帮助我指出我做错了什么或我应该以什么方式做错。预先感谢您的帮助。
这里需要在你的action方法参数中添加FromBody属性
public IActionResult Update([FromBody]Result obj)
{
.....
}
模型绑定在源中查找名称模式 prefix.property_name
。如果没有找到,它只查找 property_name
而没有 prefix.In 你的代码,asp-for
标签助手将生成如下名称:result.propertyName
。它无法与后端匹配模型。您需要使用 [Bind(Prefix ="result")]
指定前缀:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Update([Bind(Prefix ="result")]Result obj)
{
//do your stuff...
}
至于在操作中接收 IEnumerable
参数,首先您需要更改剃刀视图以将表单移到 foreach 循环之外,然后您需要将 asp-for 标签助手属性更改为 @Model.ToList()[index].PropertyName
:
@model IEnumerable<Result>
@if (Model.Count() > 0)
{
<form method="post" asp-action="Update">
@for (int i = 0; i < Model.Count(); i++)
{
<input asp-for="@Model.ToList()[i].Id" hidden />
<input asp-for="@Model.ToList()[i].Type" hidden />
<input asp-for="@Model.ToList()[i].FatId" hidden />
<div class="border p-3">
<div class="form-group row">
<h2 class="text-black-50 pl-3">Edit Result</h2>
</div>
<div class="row">
<div class="col-12">
<div class="form-group row">
<div class="col-3">
<label asp-for="@Model.ToList()[i].Section"></label>
</div>
<div class="col-3">
<label asp-for="@Model.ToList()[i].Procedure"></label>
</div>
<div class="col-3">
<label asp-for="@Model.ToList()[i].ResultDescription"></label>
</div>
<div class="col-3">
<label asp-for="@Model.ToList()[i].Passed"></label>
</div>
</div>
<div class="form-group row">
<div class="col-3">
<input asp-for="@Model.ToList()[i].Section" class="form-control" />
</div>
<div class="col-3">
<input asp-for="@Model.ToList()[i].Procedure" class="form-control" />
</div>
<div class="col-3">
<input asp-for="@Model.ToList()[i].ResultDescription" class="form-control" />
<span asp-validation-for="@Model.ToList()[i].ResultDescription" class="text-danger"></span>
</div>
<div class="col-3">
<input asp-for="@Model.ToList()[i].Passed" class="form-control" />
<span asp-validation-for="@Model.ToList()[i].Passed" class="text-danger"></span>
</div>
</div>
</div>
</div>
</div>
}
<div class="form-group row">
<div class="col-8 offset-2 row">
<div class="col">
<input type="submit" class="btn btn-info w-75" value="Save" />
</div>
</div>
</div>
</form>
}
else
{
<p>No results created yet</p>
}
控制器:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Update(IEnumerable<Result> obj)
{
return View("Mechanical", obj);
}
结果: