4

我的视图模型有一个 [Required] 不可为空的 int 属性,由 DropDownListFor 选择。如果要从中选择的列表为空,则 ModelState.IsValid 为真。

我的模型有一个必需的 int 属性:

public class MyModel
{
    [Required]
    public int PickedValue  { get; set;}

    IEnumerable<SelectListItem> Items { get; set; }
}

在我的 Create 视图中,我渲染了一个<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. PickedValueNullable( int?),或
  2. 如果我的<select>- @Html.DropDownListFor(model => model.PickedValue, model.Items, "") 中有一个空项目,或者
  3. 如果启用了客户端验证(因为从未触发该操作)。

如果POST 数据中缺少某些属性但是否有强制方法ModelState.IsValid?这不应该是默认行为吗?falseMyModel[Required]

4

1 回答 1

5

在您的情况下,我认为将 PickedValue 设为可为空的 int 可能会更好。如果您的 DropDownList 有可能没有项目,则 null 应该是 PickedValue 的可能值。

回复评论

这是有道理的,但没有回答我原来的问题......如果 MyModel 的某些属性是 [Required] 但 POST 数据中缺少,有没有办法强制 ModelState.IsValid 为假?这不应该是默认行为吗?

当涉及到 int、double、bool 和其他不能有 null 值的原语时,当 DefaultModelBinder 在 HTTP 请求中没有收到它们的数据时,它仍然必须构造一个模型实例。因此,模型被构建并且属性被初始化为其默认值。如果是 int,这意味着它将被初始化为零。由于在 HTTP 请求中没有收到任何内容,这意味着 int 永远不会被设置,因此它将始终为零。您是否尝试过为您的 int 提供 [Range] 验证器而不是 [Required] 验证器?这应该验证它不为零:

[Range(1, int.MaxValue)]
public int PickedValue  { get; set; }

我想避免更改模型,因为它已经是我的代码中的一种常见模式......另外,使模型中的属性可以为空以强制它不为空似乎违反直觉。

仅仅因为它是代码中的常见模式并不意味着它是正确的。我必须重申我原来的答案:如果您的下拉列表可能没有任何项目,那么您的模型应该允许null其选择的值。

这就是为什么最好使用单独的实体和视图模型层的原因之一。在您的域实体中,可能需要关系。但是,当用户第一次看到表单以选择该关系时,您必须给他们一个默认或空的选定下拉项。在这种情况下,实体中的外键可能是 int,但视图模型中的表示应该是Nullable<int>. 仅出于这个原因,我认为仅仅为了确保它不为空而使某些东西可以为空是不违反直觉的。您在 viewmodel 中使其可以为空,这样您就可以给用户一个带有空白值的表单,并要求他们填写它。

于 2012-06-01T15:21:33.633 回答