ModelState.IsValid为true,但POST数据中缺少[Required]属性

时间:2012-06-01 14:55:05

标签: asp.net asp.net-mvc-3

我的视图模型有一个[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.
    }
    //...
 }

现在,如果出现问题就会消失:

  1. PickedValueNullableint?)或
  2. 如果我的<select> - @Html.DropDownListFor(model => model.PickedValue, model.Items, "")或
  3. 中有空项目
  4. 如果启用了客户端验证(因为永远不会触发操作)。
  5. 如果某些ModelState.IsValid的属性为false但POST数据中缺少某些属性,是否可以强制MyModel[Required]?这不应该是默认行为吗?

1 个答案:

答案 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中将其设置为可为空,这样您就可以为用户提供一个空白值的表单,并要求他们填充它。