我知道你们中的大多数人都建议我应该使用特定于所使用表单的ViewModels,但是我很好奇为什么我的子对象没有绑定到TryUpdateModel上。
@using (Html.BeginForm()) {
@Html.ValidationSummary(true)
<fieldset>
<legend>User</legend>
@Html.HiddenFor(model => model.UserId)
@Html.HiddenFor(model => model.PrimaryAddress.AddressId)
<div class="editor-label">
@Html.LabelFor(model => model.PrimaryAddress.FirstName)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.PrimaryAddress.FirstName)
@Html.ValidationMessageFor(model => model.PrimaryAddress.FirstName)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.PrimaryAddress.LastName)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.PrimaryAddress.LastName)
@Html.ValidationMessageFor(model => model.PrimaryAddress.LastName)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.UserName)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.UserName)
@Html.ValidationMessageFor(model => model.UserName)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Email)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Email)
@Html.ValidationMessageFor(model => model.Email)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.IsApproved)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.IsApproved)
@Html.ValidationMessageFor(model => model.IsApproved)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.IsEmployee)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.IsEmployee)
@Html.ValidationMessageFor(model => model.IsEmployee)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
和控制器代码:
[HttpPost]
public ActionResult Edit(int id, FormCollection form)
{
var user = Token.DB.Users.Include("PrimaryAddress").Single(x => x.UserId == id);
if (TryUpdateModel(user, new string[] { "UserName", "Email", "IsApproved", "IsEmployee", "PrimaryAddress.FirstName", "PrimaryAddress.LastName" }))
{
try
{
Token.DB.SaveChanges();
return RedirectToAction("index");
}
catch (Exception ex)
{
while (ex.InnerException != null)
ex = ex.InnerException;
if (ex.Message.ToLowerInvariant().Contains("unique"))
ModelState.AddModelError("UserName", "UserName already exists");
}
}
return View(User);
}
该代码不会引发任何异常,只是不会从表单中填充user.PrimaryAddress.FirstName或user.PrimaryAddress.LastName。我想知道为什么吗?
我已经知道我可以使用特定的ViewModel并在后台映射信息来解决此问题。我也可以这样做:
<!-- Edit.cshtml -->
<div class="editor-field">
@Html.EditorFor(model => model.PrimaryAddress.FirstName, null, "FirstName")
@Html.ValidationMessageFor(model => model.PrimaryAddress.FirstName)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.PrimaryAddress.LastName)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.PrimaryAddress.LastName, null, "LastName")
@Html.ValidationMessageFor(model => model.PrimaryAddress.LastName)
</div>
// UsersController.cs
if (TryUpdateModel(user, new string[] { "UserName", "Email", "IsApproved", "IsEmployee"})
&& TryUpdateModel(user.PrimaryAddress, new string[] {"FirstName", "LastName" }))
因此,真正的问题是,为什么在第一个示例中它不具有约束力?
最佳答案
因此,真正的问题是,为什么在第一个示例中它不具有约束力?
您的问题的答案非常简单:UpdateModel,TryUpdateModel或[Bind]
属性在包含/排除属性列表中都不支持“嵌套属性”。因此,请正确处理并使用视图模型。防范大规模财产转让攻击只是应使用视图模型的数百万个原因之一。好吧,您似乎找到了通过执行第二个TryUpdateModel
的解决方法,但是如果您在此域对象上具有许多属性,则控制器操作代码可能会迅速变成意大利面条管道代码。