我的视图模型有一个[Required]非可空int属性,由DropDownListFor选择。如果要选择的列表为空,则ModelState.IsValid为true。
我的模型有一个必需的int属性:
public class MyModel
{
[Required]
public int PickedValue { get; set;}
IEnumerable<SelectListItem> Items { get; set; }
}
在我的“创建”视图中,我呈现了一个<select>
元素:
@Html.DropDownListFor(model => model.PickedValue, model.Items)
在我的控制器中,如果model.Items
列表为空(没有可供选择的元素),ModelState.IsValid
为真:
[HttpPost]
public ActionResult Create( MyModel model )
{
if( ModelState.IsValid )
{
// true, and ModelState.Keys doesn't contain PickedValue because it was never POSTed.
}
//...
}
现在,如果出现问题就会消失:
PickedValue
是Nullable
(int?
)或<select>
- @Html.DropDownListFor(model => model.PickedValue, model.Items, ""
)或如果某些ModelState.IsValid
的属性为false
但POST数据中缺少某些属性,是否可以强制MyModel
为[Required]
?这不应该是默认行为吗?
答案 0 :(得分:4)
在你的情况下,我认为让PickedValue成为可以为空的int可能会更好。如果您的DropDownList有可能没有项目,那么null应该是PickedValue的可能值。
回复评论
这是有道理的,但没有回答我原来的问题......是否有 如果某些MyModel的话,强制ModelState.IsValid为false的方法 属性是[必需],但POST数据中缺少? 这不应该是默认行为吗?
当涉及到int,double,bools和其他不具有null值的原语时,当DefaultModelBinder在HTTP请求中没有收到它们的数据时,它仍然必须构造一个模型实例。因此,构建模型并将属性初始化为其默认值。在int的情况下,这意味着它将被初始化为零。由于HTTP请求中没有收到任何内容,这意味着int永远不会被设置,因此它将始终为零。你试过给你的int一个[Range]验证器而不是[Required]验证器吗?这应该验证它不是零:
[Range(1, int.MaxValue)]
public int PickedValue { get; set; }
我想避免更改模型,因为它已经很常见了 我的代码中的模式...加上模型中的属性可以为空 强迫它不为空似乎是违反直觉的。
仅仅因为它是代码中的常见模式并不意味着它是正确的。我必须重申我的原始答案:如果您的下拉列表中没有任何项目,那么您的模型应该允许null
获取其选定的值。
这就是为什么将单独的实体和实体分开是一个好习惯的原因之一。 viewmodel图层。在您的域实体中,可能需要关系。但是,当首次向用户显示选择该关系的表单时,您必须为其提供默认或空的选定下拉项。在这种情况下,实体中的外键可能是int,但viewmodel中的表示应该是Nullable<int>
。仅仅因为这个原因,我认为让一些可以为空的东西只是为了确保它不是空的,这是违反直觉的。您可以在viewmodel中将其设置为可为空,这样您就可以为用户提供一个空白值的表单,并要求他们填充它。