简体   繁体   English

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

[英]Disable Model Validation in Asp.Net MVC

How do I disable Model validation for a single Action in a Controller ? 如何在Controller中禁用单个Action的模型验证? Or can I do it per model by registering the model type at startup somewhere ? 或者我可以通过在启动时注册模型类型来为每个模型执行此操作吗?

I want the ModelBinder to bind to the model, but afterwards it should not perform the model validation. 我希望ModelBinder绑定到模型,但之后它不应该执行模型验证。

The reason why i dont want validation to happen is because i am trying to move the logic from the controllers to a service layer which will be responsible for validating the models as i cant assume that models being passed to a service contains valid data. 我不希望验证发生的原因是因为我试图将逻辑从控制器移动到服务层,该服务层将负责验证模型,因为我不能假设传递给服务的模型包含有效数据。

As I understand this is the recommend approach (to not have logic in the controllers), so I find it a bit strange that i cant seem to find anything about how the model validation can be disabled (per action or per model type). 据我所知,这是推荐的方法(在控制器中没有逻辑),所以我觉得有点奇怪,我似乎无法找到任何关于如何禁用模型验证(每个动作或每个模型类型)。

Please notice that I dont want to disable model validation for the entire webapplication (by removing the validation providers), and i dont want to disable the input validation that checks for malicious code being posted. 请注意,我不想禁用整个Web应用程序的模型验证(通过删除验证提供程序),并且我不想禁用检查发布的恶意代码的输入验证。


UPDATE UPDATE

I am using .Net 4.0 and MVC 3 Preview 1 我正在使用.Net 4.0和MVC 3预览1

Just remove the items you don´t need before checking if the model is valid 在检查模型是否有效之前,只需删除不需要的项目

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

I've solved this problem with this code: 我用这段代码解决了这个问题:

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

Not sure it's the right way though. 不确定这是正确的方式。

Unfortunately there seems to be no easy way to disable the model validation happening in the ModelBinder except for registering every single model type you don't want to validate (including nested complex types) with a specific ModelBinder. 遗憾的是,除了使用特定的ModelBinder注册您不想验证的每个模型类型(包括嵌套复杂类型)之外,似乎没有简单的方法来禁用ModelBinder中发生的模型验证。 It can be done with the following code: 可以使用以下代码完成:

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

Creating a SkipValidationAttribute that can be attached to action methods or action method parameters doesn't seem possible as it should be implemented in the ControllerActionInvoker, but there is no way of letting the ModelBinder know that it should do any validation in the SetProperty() and OnModelUpdated methods when calling BindModel() in the GetParameterValue() method. 创建一个可以附加到操作方法或操作方法参数的SkipValidationAttribute似乎不可能,因为它应该在ControllerActionInvoker中实现,但是没有办法让ModelBinder知道它应该在SetProperty()中进行任何验证。在GetParameterValue()方法中调用BindModel()时的OnModelUpdated方法。

I would recommend you perform validation in both places rather than trying to turn off validation in the UI. 我建议您在两个地方执行验证,而不是尝试在UI中关闭验证。 I understand your point that the service cannot assume that it's being passed valid data - that is a valid concern and is the reason your service should have validation. 我理解您的观点,即服务不能假定它正在传递有效数据 - 这是一个有效的问题,也是您的服务应该进行验证的原因。 But you should also have validation in your UI. 但是您应该在UI中进行验证。 This is also nice because you can have client-side validation to prevent user errors and give you users a better experience. 这也很好,因为您可以进行客户端验证以防止用户错误并为您提供更好的体验。

I definitely dislike this addition in the 2.0 version, because, as you stated in your question, validation makes more sense in the Service layer. 我绝对不喜欢2.0版本中的这个添加,因为正如您在问题中所述,验证在服务层中更有意义。 In this way you can reuse it in other non-web applications, and test it more easily without having to mock the auto-validation mechanism. 通过这种方式,您可以在其他非Web应用程序中重用它,并且无需模拟自动验证机制就可以更轻松地对其进行测试。

Validation in Controller layer is pointless because in this part you can only verify model data and not business rules. Controller层中的验证毫无意义,因为在这部分中,您只能验证模型数据而不是业务规则。 For example, think of a service responsible of adding new comments and a user that wants to post a new one, the data in the comment he/she is posting may be valid, but what happens if the user is banned to comment because of misbehavior in the past? 例如,考虑一个负责添加新评论的服务和一个想要发布新评论的用户,他/她发布的评论中的数据可能是有效的,但如果用户由于行为不当而被禁止发表评论会发生什么?在过去? You should do some validation in the Service layer to ensure this is not happening, and if it does, throwing an exception. 您应该在服务层中进行一些验证,以确保不会发生这种情况,如果发生这种情况,则抛出异常。 In short, validation must be done in the Service layer. 简而言之,必须在服务层中进行验证。

I use xVal as my Validation framework because it's compatible with the DataAnnotationModel, allows me to place validation wherever I want and performs client-side validation without extra-effort, even remote-client side. 我使用xVal作为我的验证框架,因为它与DataAnnotationModel兼容,允许我在任何地方放置验证并执行客户端验证而不需要额外的努力,甚至是远程客户端。 This is how I use it at the beginning of each of my services, for example, a login service: 这是我在每个服务开始时使用它的方式,例如登录服务:

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...
}

Simple, web-independent and easy... then, in the 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"));
}

I know that this already been answered but what you really needed was to extend the DataAnnotationsValidatorProvider and override the GetValidators method. 我知道这已经得到了回答,但你真正需要的是扩展DataAnnotationsValidatorProvider并覆盖GetValidators方法。

Then, on startup, you would remove the DataAnnotationsValidatorProvider from ModelValidatorProviders.Providers and add your new one. 然后,在启动时,您将从ModelValidatorProviders.Providers删除DataAnnotationsValidatorProvider并添加新的。

Needless to say, if you simply don't want any validation at all, you can simply have the GetValidators method returning an empty collection. 毋庸置疑,如果您根本不想进行任何验证,只需让GetValidators方法返回一个空集合即可。

In my case, I need to remove validation only when submitting the forms while still keeping the client-side validation, hence the following: 在我的情况下,我需要在提交表单时删除验证,同时仍然保持客户端验证,因此以下内容:

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);
    }
}

I use [ ValidateInput( false )] 我用[ValidateInput(false)]

Not sure if this prevents model validation, or only IIS submit validation. 不确定这是否会阻止模型验证,还是仅阻止IIS提交验证。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM