禁用Asp.Net MVC中的模型验证

时间:2010-08-26 19:30:30

标签: asp.net-mvc model-view-controller validation model

如何为Controller中的单个Action禁用模型验证? 或者我可以通过在某处启动时注册模型类型来为每个模型执行此操作吗?

我希望ModelBinder绑定到模型,但之后它不应该执行模型验证。

我不希望验证发生的原因是因为我试图将逻辑从控制器移动到服务层,该服务层将负责验证模型,因为我无法假设传递给服务的模型包含有效数据

据我所知,这是推荐的方法(控制器中没有逻辑),所以我觉得有点奇怪,我似乎无法找到关于如何禁用模型验证的任何事情(每个动作或每个模型类型) )。

请注意,我不想禁用整个Web应用程序的模型验证(通过删除验证提供程序),并且我不想禁用检查发布的恶意代码的输入验证。


更新

我正在使用.Net 4.0和MVC 3预览1

7 个答案:

答案 0 :(得分:11)

在检查模型是否有效之前,只需删除不需要的项目

ModelState.Remove("Email");
if (ModelState.IsValid)
{
   // your logic
}

答案 1 :(得分:10)

我用这段代码解决了这个问题:

public ActionResult Totals(MyModel model)
{
    ModelState.Clear();
    return View(model);
}

不确定这是正确的方法。

答案 2 :(得分:3)

不幸的是,似乎没有简单的方法来禁用ModelBinder中发生的模型验证,除了使用特定的ModelBinder注册您不想验证的每个模型类型(包括嵌套复杂类型)。可以使用以下代码完成:

ModelBinders.Binders[typeof(MyModelType)] = new NonValidatingModelBinder();

创建可附加到操作方法或操作方法参数的SkipValidationAttribute似乎不可能,因为它应该在ControllerActionInvoker中实现,但是没有办法让ModelBinder知道它应该在SetProperty中进行任何验证在GetParameterValue()方法中调用BindModel()时的()和OnModelUpdated方法。

答案 3 :(得分:2)

我建议您在两个位置执行验证,而不是尝试在UI中关闭验证。我理解您的观点,即服务不能假定它正在传递有效数据 - 这是一个有效的问题,也是您的服务应该进行验证的原因。但是你应该在你的UI中进行验证。这也很好,因为您可以进行客户端验证以防止用户错误并为用户提供更好的体验。

答案 4 :(得分:2)

我绝对不喜欢2.0版本中的这个添加,因为正如您在问题中所述,验证在服务层中更有意义。通过这种方式,您可以在其他非Web应用程序中重用它,并且无需模拟自动验证机制就可以更轻松地进行测试。

Controller层中的验证毫无意义,因为在这部分中,您只能验证模型数据而不是业务规则。例如,考虑一个负责添加新评论的服务和一个想要发布新评论的用户,他/她发布的评论中的数据可能是有效的,但如果用户由于行为不当而被禁止发表评论会发生什么?在过去?您应该在服务层中进行一些验证,以确保不会发生这种情况,如果发生这种情况,则抛出异常。简而言之,必须在服务层中进行验证。

我使用xVal作为我的验证框架,因为它与DataAnnotationModel兼容,允许我在任何地方进行验证并执行客户端验证而不需要额外的努力,甚至是远程客户端。这就是我在每个服务开始时使用它的方式,例如登录服务:

public void SignIn(Login login) {
    var loginErrors = DataAnnotationsValidationRunner.GetErrors(login);

    // Model validation: Empty fields?
    if (loginErrors.Any())
        throw new RulesException(loginErrors);

    // Business validation: Does the user exist? Is the password correct?
    var user = this._userRepository.GetUserByEmail(login.Email);

    if (user == null || user.Password != login.Password)

        throw new RulesException(null, "Username or password invalids");

    // Other login stuff...
}

简单,独立于网络,简单......然后,在Controller中:

public RedirectResult Login(Login login) {

    // Login the user

    try {

        this._authenticationRepository.SignIn(login);

    } catch (RulesException e) {

        e.AddModelStateErrors(base.ModelState, "Login");

    }

    // Redirect

    if (base.ModelState.IsValid)
        return base.Redirect(base.Url.Action("Home"));
    else return base.Redirect(base.Url.Action("Login"));
}

答案 5 :(得分:0)

我知道这已经得到了解答,但您真正需要的是扩展DataAnnotationsValidatorProvider并覆盖GetValidators方法。

然后,在启动时,您会从DataAnnotationsValidatorProvider中移除ModelValidatorProviders.Providers并添加新的。{/ p>

毋庸置疑,如果您根本不想进行任何验证,只需让GetValidators方法返回一个空集合即可。

在我的情况下,我需要在提交表单时删除验证,同时仍然保持客户端验证,因此如下:

public class DynamicModelValidatorProvider : DataAnnotationsModelValidatorProvider
{
   GetValidators(ModelMetadata metadata, ControllerContext context, IEnumerable<Attribute> attributes)
    {
        if (context.HttpContext.Request.HttpMethod == "POST")
        {
            return new ModelValidator[] { };
        }

        return base.GetValidators(metadata, context, attributes);
    }
}

答案 6 :(得分:-3)

我用 [ValidateInput(false)]

不确定这是否会阻止模型验证,还是仅阻止IIS提交验证。