Disable Model Validation in Asp.Net MVC

33,364

Solution 1

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

Solution 2

Just remove the items you don´t need before checking if the model is valid

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

Solution 3

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.

Solution 4

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

Validation in Controller layer is pointless because in this part you can only verify model data and not business rules. 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. 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"));
}

Solution 5

I would recommend you perform validation in both places rather than trying to turn off validation in the 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. This is also nice because you can have client-side validation to prevent user errors and give you users a better experience.

Share:
33,364
iCeStar
Author by

iCeStar

LinkedIn: https://www.linkedin.com/in/martinfrom/

Updated on October 22, 2020

Comments

  • iCeStar
    iCeStar over 3 years

    How do I disable Model validation for a single Action in a Controller ? 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.

    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.


    UPDATE

    I am using .Net 4.0 and MVC 3 Preview 1

  • iCeStar
    iCeStar over 13 years
    It doesnt prevent the model from being validated. As far as i know it is used to disable the check for malicious input (like html tags or javascript etc.)
  • iCeStar
    iCeStar over 13 years
    Thanks for your reply. I have clientside UI validation. I use the attributes in the DataAnnotations namespace for my models. My service layer adds the validation errors to the Modelstate (if in a web context). There is no reason to perform the same validation twice. :)
  • iCeStar
    iCeStar over 13 years
    Basically my service layer follows this approach asp.net/mvc/tutorials/validating-with-a-service-layer--cs It works fine, but the example doesnt use the DataAnnotations attributes for validation, which are automatically validated in MVC (and what i am trying to prevent).
  • Steve Michelotti
    Steve Michelotti over 13 years
    That link doesn't have a date as to when it was written but my guess is that it's pretty old. When MVC was first released, there was some confusion around where validation logic should go (controller, etc.). But that story has been solidified in the last year or so with the recommended best practice typically being that UI validation should happen in the model binder which is why that's now the default in MVC 2.
  • Steve Michelotti
    Steve Michelotti over 13 years
    If you are set on doing it this way, then it could be accomplish by inheriting the DataAnnotationModelBinder and then override the OnModelUpdated() method and inside just do ModelState.Clear(). I'm not saying I would do this though. :)
  • iCeStar
    iCeStar over 13 years
    I assume you are talking about the DefaultModelBinder (as there is no DataAnnotationsModelBinder - there is a DataAnnotationsModelValidator though). Doing a ModelState.Clear() inside the ModelBinder will affect the entire WebApplication which i dont want to, i want it to keep working the traditional way, but be able to disable the model validation either per action or per model type. I could of course make a big switch or if clause and add every single Model type that i dont want validated - but that would be pretty ugly i guess - but maybe it is the best option! :)
  • iCeStar
    iCeStar over 13 years
    I can see that the OnModelUpdated method gets a ControllerContext and a ModelBindingContext. The best option would be if it is somehow possible to figure out which Action is being called and then check if it has a Custom attribute (ValidateModel etc) attached to it to prevent it from validating the model. Another option is to register a ModelBinder that doesnt do the validation, and register every single type - something like ModelBinders.Binders[typeof(MyModelType)] = new NonValidatingModelBinder(); Thanks for replying. There is a couple of options that i can try to work on. :)
  • Steve Michelotti
    Steve Michelotti over 13 years
    Yes, I meant to say "DefaultModelBinder". I would use your second approach: ModelBinders.Binders[typeof(MyModelType)] = new NonValidatingModelBinder();. That way it doesn't affect your application globally.
  • iCeStar
    iCeStar over 13 years
    Just to give a small update (if it has any interest to you), it is possible to attach attributes to parameters (like the BindAttribute), so it should be easy to check if the parameter/model have an attribute attached in the OnModelUpdated and just disable the validation if it have. So when i dont need model validation i can just disable it by doing something like public ActionResult ActionMethodName ([DisableModelValidation] MyModelType model) {...} :)
  • iCeStar
    iCeStar over 13 years
    I made the " SkipValidationAttribute" approach work, by creating my own impl of ControllerActionInvoker which gets the attribute from the method parameter and if it is declared it adds a key to the modelstate injected into the ModelBinder (BindModel method), and remove it again when the model is bound. Then i can check in the ModelBinder if the modelstate contains the key and if it does it skips validation, if not just performs validation like it normally would.
  • Rubens Mariuzzo
    Rubens Mariuzzo over 11 years
    This one is more faster & easy!
  • Honorable Chow
    Honorable Chow about 10 years
    As a usability specialist I disagree. Users hate not getting all the validations at once. Unless you duplicate them all splitting them is bad form.
  • Honorable Chow
    Honorable Chow about 10 years
    Model state data does more than hold validation. By clearing the model state you will lose other functionality as well.
  • iCeStar
    iCeStar over 9 years
    @Kugel: Even though way to late, NonValidatatingModelBinder you have to implement yourself.
  • Thomas.Benz
    Thomas.Benz over 7 years
    This is short, clean and does help.