【问题标题】:Not receiving ModelState error when ommitting int property省略 int 属性时未收到 ModelState 错误
【发布时间】:2014-03-11 12:07:37
【问题描述】:

我在 MVC4 中发现了一些让我感到困惑的功能。我有以下模型和控制器操作:

public class MyModel
{
    public int Foo { get; set; }
}

public ActionResult MyAction(MyModel model)
{
    // check ModelState.IsValid and do stuff
}

我遇到的问题是,如果我向 MyAction 发出 GET 请求并且不传递任何参数,则 ModelState.IsValid 为真。如果我将 Foo 作为参数传入,并以空字符串作为值,则 ModelState.IsValid 如预期的那样为 false(带有需要 Foo 的错误消息)。

所以我想我的问题是,当省略 Foo 时,为什么 ModelState.IsValid 为真?这是 MVC 中的错误还是我只是遗漏了什么?如果需要某个属性,则在省略该属性时似乎应该出现 ModelState 错误。

只是为了好玩,我尝试将 Foo 更改为字符串并向其添加 [Required] 属性。当我这样做时,上述两个测试都为 ModelState.IsValid 返回 false,这也是我期望它对不可为空的 int 属性所做的事情。在此测试之后,我将 Foo 改回 int 并留下 [Required] 属性以查看是否有任何效果。仍然得到与没有 [Required] 属性的 int 相同的结果。

【问题讨论】:

  • 你确定Foo在你省略时为空,还是默认为0?我猜 Foo 会是 0 并且没有 [Required] 属性它会通过验证。
  • @Brandon 我从未说过 Foo 在省略时为空。在这两种情况下它都是 0,但只有一种情况会引发 ModelState 错误。并且当被省略时,它会通过有或没有 [Required] 属性的验证(当 Foo 是一个 int 时)。
  • 我猜不同之处在于,一个不可为空的int 在模型中通过时将有一个值,而标记中没有该字段。那是零。但是,如果 string 未在标记中通过,则 null 将是 null。对我来说很有意义(不是错误)。
  • @SimonWhitehead 那么,您将如何使 int 成为必需的,以便在省略和作为空表单参数提交时给您一个 ModelState 错误?我已经看到它可以使用字符串属性来完成,但到目前为止还无法使用 int 属性来完成。
  • @SimonWhitehead 从概念的角度来看,如果您在模型中指定一个字段是必需的(在这种情况下,通过使其不可为空),则不为在您的 http 请求中应该意味着模型的状态无效......让一个不可为空的值允许空值似乎违反直觉,这就是这种行为所表明的。

标签: c# asp.net-mvc asp.net-mvc-4


【解决方案1】:

西蒙在cmets中说的是正确的。

如果您不将 int 传递给模型,则它默认为 0,而字符串将作为 null 传入并且无法通过 Required 检查。

如果你想强制使用整数,你应该使用可以为空的类型。这样可以确保它默认为 null 而不是 0。

[Required]
public int? Foo { get; set; }

【讨论】:

  • 这在技术上是可行的,但绕过一个 bug 感觉有点像 hack。似乎有点倒退,使某些东西可以为空,然后说它是必需的。
【解决方案2】:

如果我不得不在黑暗中冒险,我会说这是导致这种情况发生的 DefaultModelBinder 类中的代码点:

    protected virtual void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor)
    {
        // need to skip properties that aren't part of the request, else we might hit a StackOverflowException
        string fullPropertyKey = CreateSubPropertyName(bindingContext.ModelName, propertyDescriptor.Name);
        if (!bindingContext.ValueProvider.ContainsPrefix(fullPropertyKey))
        {
            return;
        }

如果 ValueProvider 中没有提供属性名称(在最简单的情况下这只是请求参数),那么它会跳过它……显然是为了防止在某些情况下无限递归。我想这在嵌套模型的情况下是有意义的,例如:

class Foo
{
    public Foo InnerFoo { get; set; }
}

这样做似乎有点短视(或者我的诊断可能有点短视......),即因为像这个确切的帖子这样的情况。

我称之为错误,除非更聪明的人可以纠正我。

适当的解决方法是 @Brandon 的 answer 建议:

[Required]
public int? Foo { get; set; }

然后继续生活......我们都写过比我敢肯定的更丑陋的东西:)

【讨论】:

    猜你喜欢
    • 2020-08-21
    • 1970-01-01
    • 2015-07-25
    • 1970-01-01
    • 1970-01-01
    • 2019-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多