我有一个这样的模型:
public class Person
{
public int ID { get; set; }
[Required(ErrorMessage="Name cant be empty")]
public string Name { get; set; }
public Person Friend { get; set; }
}
我想创建一个新的 Person,并使用强类型 HtmlHelper 制作一个包含字段的表单
- 身份证
- 姓名
- 好友 ID(包含
<option value="Friend.ID">Friend.Name</option>
等选项的下拉列表
发布表单时,我的 Controller 接收一个 Person 对象 ( p
),该对象使用默认的 modelbinder 进行绑定(bind)。明确地说,模型绑定(bind)器执行以下操作:ID
和Name
属性按预期绑定(bind)。 Friend
设置为新的Person
实例 ID
等于我在下拉列表中选择的人的 ID。 Friend.Name
的值为null
因为我没有在表单中提供它的值。
问题:我想要RequiredAttribute
开火Name
文本框,如果它是空的 - 确实如此。问题是它也会在 Friend
上触发的名称属性。因此,当我发布并填写所有字段时,我发现 ModelState 无效,错误是 p.Friend.Name
是必须的。
我该如何解决这个问题?当然,在这种情况下,我不想验证 Friend
的属性。我想到过:
- 使用 ViewModels 来表达我的观点,这会以某种方式解决我的问题。我还没有尝试过,因为我觉得对于这么简单的问题我真的不需要这样做
- 将 friend 的 ID 作为单独的参数发送,
friend_id
,并绑定(bind)Friend
手动属性。只有ID
和Name
发布者的属性已绑定(bind),我手动设置Friend
属性(property)。这涉及获取Friend
使用friend_id
从我的存储库中使其成为“真正的”Person 对象。 - 检查 ModelState 并删除我知道的错误不算数。这完全是错误的并且不可扩展(如果我添加例如
SecondFriend
属性,则必须记住这样做
我觉得选项 2 是最可行的,但理想情况下我希望它是自动的。此外,我无法使用强类型帮助程序,如 friend_id
文本框'name
属性必须与操作方法的参数名称匹配。
我觉得我错过了一些可以让这件事变得更容易的点。希望我是对的。虽然我认为使用 ViewModel 有点乏味,但这是正确的做法,请告诉我。
编辑
现在使用 ViewModels 解决了问题 ID
, Name
和Friend_id
其属性和与 Person
相同的验证属性模型。然后我映射 ID
和Name
值变为新的Person
实例。然后通过从存储库加载指定的好友来设置 Friend 属性。喜欢newPerson.Friend = repository.Get(viewModel.Friend_id)
当我有时间时,我计划仔细观察 AutoMapper “自动”执行此操作。
最佳答案
问题是模型状态字典键只有属性名称作为键。因此,在您的情况下,其中有两个具有相同的 key :Person
上的 Name
和 Friend
上的 Name
.
我一直在努力让这样的事情发挥作用。如果键名称具有类似于 VarName.PropertyName
的表示法,那就最好了。在这种情况下它会起作用,因为你有两个不同的:
p.Name
p.Friend.Name
拥有 ClassName.PropertyName
是行不通的,因为您可能有两个类型相同但名称不同的操作参数。
但是应该如何解决这个问题呢?一种方法是创建您自己的操作过滤器来执行模型验证并填充模型状态错误(首先将其全部清除)。这也意味着您必须使用 Html 扩展方法的非 lambda 版本。因此,您必须使用 Html.TextBox
扩展程序并提供自定义键,而不是 Html.TextBoxFor
。
为了使 View 方面的内容更加通用,您当然可以编写自己的 Html 扩展重载(您使用的扩展重载),该重载将采用参数名称的附加参数,例如:
Html.TextBoxFor("p", model => model.Friend.Name);
然后会生成
<input type="text" name="p.Friend.Name" id="p_Friend_Name" />
相信我,默认模型绑定(bind)器将能够使用这些类型的输入名称。它具有参数名称及其属性的知识。
关于asp.net-mvc - 验证传播到相关对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3702496/