我正在尝试将“产品规范”列表绑定(bind)到我的“添加产品”对话框。提交是使用 AJAX 执行的。
因为我允许用户在同一个表单上上传产品图片,所以我发送带有“FormData”对象的 AJAX 请求来代替序列化。
结果是,由于规范列表不是 Controller 预期的格式,因此永远不会达到 Controller 操作。
ProductModalViewModel
public class ProductModalViewModel
{
public ProductModalViewModel()
{
Product = new Product();
Specs = new List<Spec>();
}
public Product Product { get; set; }
//Other properties removed for brevity
public List<Spec> Specs { get; set; }
}
View (模态)
<form id="formSaveProduct" onsubmit="SaveProduct(event)" enctype="multipart/form-data">
<input type="hidden" asp-for="Product.Id" />
//Removed other form fields for brevity
<div class="specs-list-group">
<ul class="list-group">
@for (int i = 0; i < Model.Specs.Count(); i++)
{
<li class="list-group-item">
<input type="hidden" asp-for="@Model.Specs[i].Id" />
<div class="row">
<div class="col-5">
<input type="text" asp-for="@Model.Specs[i].Name" />
</div>
<div class="col-5">
<input type="text" asp-for="@Model.Specs[i].Value" />
</div>
</div>
</li>
}
</ul>
</div>
</form>
脚本
function SaveProduct(e) {
e.preventDefault(); // prevent standard form submission
$.ajax({
url: "@Url.Action("SaveProduct", "ProductManagement", new { Area = "Admin" })",
method: "post",
data: new FormData($('#formSaveProduct')[0]),
contentType: false,
processData: false,
success: function (result) {
if (result.success) {
$("#exampleModal").modal('toggle');
location.reload();
}
else {
$(".modal-body").html(result);
}
},
error: function (e) {
alert("Error: " + e.status)
}
});
}
Controller
[HttpPost]
public ActionResult SaveProduct(ProductModalViewModel model)
{
//Save
}
请求头
FormData:
Product.Id: 1
Product.Brand: Browning
Product.Model: Gold Mossy Oak Shadow Grass Blades
Product.ProductNum: 723654
Product.CategoryId: 4
Product.IsActive: true
Product.Overview: This is an overview of the tkjsldfgn jlfdgl-sdfgn lkjgfnjkl dfsngkl kjlngkldf jngjkln kdfjnggf h sd sdfgdf...
Specs[0].Id: 1
Specs[0].Name: Test Spec 1
Specs[0].Value: Test Value 1
Specs[1].Id: 2
Specs[1].Name: Test Spec 2
Specs[1].Value: Test Value 2
Specs[2].Id: 3
Specs[2].Name: Test Spec 3
Specs[2].Value: Test Value 3
在我添加规范列表之前,此表单完全可以正常工作。在使用 FormData 对象时,我需要更改什么才能绑定(bind)列表?
编辑:添加了用于故障排除引用的规范实体。
public class Spec
{
[Key]
public int Id { get; set; }
public Spec(string name, string value)
{
Name = name;
Value = value;
}
[Required]
public string Name { get; set; }
[Required]
public string Value { get; set; }
[ForeignKey("Product")]
[Required]
public int ProductId {get; set; }
public virtual Product Product { get; set; }
//Timestamps
public DateTime? Created { get; set; }
public DateTime? Modified { get; set; }
}
最佳答案
修改 Controller 操作中的模型参数以使用 [FromForm]
属性:
[HttpPost]
public ActionResult SaveProduct([FromForm]ProductModalViewModel model)
{
//Save
}
您可以阅读更多关于绑定(bind)行为的信息 here .
更新:
我怀疑您的问题来自两方面:
- 您的
Spec
类没有无参数构造函数 - ProductId 是 [必需],但您没有在 POST 中传递产品 ID
这是我的建议:
您真的不应该将实体模型放入您的 View 中。
我建议您创建一个名为 SpecDto
的新类并遵循这些规则
- 只添加您希望从客户提交的属性
- 有一个无参数的构造函数。
- 只使用相关属性。不要使用实体相关的属性,如
[ForeignKey("Product")]
像这样:
public class SpecDto
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Value { get; set; }
public int ProductId { get; set; }
public DateTime? Created { get; set; }
public DateTime? Modified { get; set; }
}
你应该对产品做同样的事情。
那么你的 ViewModel 应该是这样的:
public class ProductModalViewModel
{
public ProductModalViewModel()
{
Product = new ProductDto();
Specs = new List<SpecDto>();
}
public ProductDto Product { get; set; }
public List<SpecDto> Specs { get; set; }
}
然后在您的 Controller 中,将数据从 DTO 类传输到您的实体模型。我知道这看起来很乏味,但这是做这些事情的正确方法。如果你有一个大项目,请使用 AutoMapper传输数据。如果您的项目范围真的很小,那么也许您可以争论在您的 View 中使用实体模型的案例,但通常这不是一个好主意。
关于javascript - 使用 AJAX 和 FormData 在 POST 上绑定(bind)列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56280415/