Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to disable MVC 4 model validation?

I am working on a project written on mvc 4 that got several instances of wizard-like behaviour - chain of few views that pass the same half-filled model. Starting from the second view controls are initially shown as non-valid (which is logical - model, passed to controller method has corresponding properties empty). Currently ModelState.Clear(); solution is used, but putting it into each method with model as an argument looks ugly. Same with approach found here Disable Model Validation in Asp.Net MVC

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

Project got too many (over 100) model classes to register each one manually.

Is there simpler way (maybe key in .config) that turns off model validation completely?

like image 518
user1782982 Avatar asked Oct 29 '12 13:10

user1782982


People also ask

How do I turn off client side validation?

To disable client-side validation, set the page's ClientTarget property to 'Downlevel' ('Uplevel' forces client-side validation). Alternatively, you can set an individual validator control's EnableClientScript property to 'false' to disable client-side validation for that specific control.

Can I stop the client side validation of an entire page?

You can also disable a validation control so that it is not rendered to the page at all and no validation takes place using that control. If you want to perform validation on the server but not on the client, you can set an individual validation control to not emit client-side script.


2 Answers

I don't know it this could work but did you try this (bootstrap code or global.asax)

ModelValidatorProviders.Providers.Clear();
like image 79
Tomasz Jaskuλa Avatar answered Sep 30 '22 08:09

Tomasz Jaskuλa


I know it doesn't really answer your question, but just to expand on my comment:-

It sounds like you have something like:-

public class MyModel
{
  [Required]
  public string Foo { get; set; } // Populated in step 1
  [Required]
  public string Bar { get; set; } // Populated in step 2
}

You have a problem when you POST step 1 because the user hasn't entered a value for Bar yet, so there's a ModelStateError.

My preferred solution, rather than trying to mess around with validation of your persistence model, would be to decouple your View implementation from your Model implementation with a ViewModel for each Wizard step, for example:-

public class MyModel
{
  [Required]
  public string Foo { get; set; }
  [Required]
  public string Bar { get; set; }
}

public class StepOneModel
{
  [Required]
  public string Foo { get; set; }
}

public class StepTwoModel
{
  // This really depends on the behaviour you want.
  // In this example, the model isn't persisted until
  // the last step, but you could equally well persist
  // the partial model server-side and just include a
  // key in subsequent wizard steps.
  [Required]
  public StepOneModel StepOne { get; set; }

  [Required]
  public string Bar { get; set; }
}

Your controller actions look something like:-

public ActionResult StepOne()
{
  return View(new StepOneViewModel());
}
[HttpPost]
public ActionResult StepOne(StepOneViewModel model)
{
  if(ModelState.IsValid)
  {
    var stepTwoModel = new StepTwoViewModel ()
    {
      StepOne = model
    };

    // Again, there's a bunch of different ways
    // you can handle flow between steps, just
    // doing it simply here to give an example
    return View("StepTwo", model);
  }

  return View(model);
}
[HttpPost]
public ActionResult StepTwo(StepTwoViewModel model)
{
  if (ModelState.IsValid)
  {
    // You could also add a method to the final ViewModel
    // to do this mapping, or use something like AutoMapper
    MyModel model = new MyModel()
    {
      Foo = model.StepOne.Foo
      Bar = model.Bar
    };

    this.Context.MyModels.Add(model);
    this.Context.SaveChanges();
  }

  return View(model);
}

Your StepOne view looks something like:-

@model StepOneModel
@using (html.BeginForm()) {
   @html.EditorFor(x => x.Foo);
}

Your StepTwo view looks something like:-

@model StepTwoModel
@using (html.BeginForm("StepTwo")) {
  @html.HiddenFor(x => x.StepOne);
  @html.EditorFor(x => x.Bar);
}

The major advantage compared to just turning off model validation is that you can put the validation requirements for the current step on your ViewModel - you can ensure that all the values from step one are valid before proceeding to step two.

  • If you want a more RESTful approach (where your controller doesn't care that the data is coming from a wizard-style view) another popular solution is to wrap each step in a <div> client-side and use javascript to hide/show them as the user progresses.

  • If your model needs to be persisted between steps, then you'll need to think about the ValidationAttributes on your model, and what they mean. If you've annotated User.DateOfBirth with Required, but you need to be able to persist it before the step it gets populated, then in fact User.DateOfBirth isn't required (e.g. EF CodeFirst can't make the column NOT NULL because we need to be able to persist null values in the meantime). You'll need to do some conditional validation (e.g. IValidatableObject, MvcFoolproof, Fluent Validation) in order to validate your complete model later.

like image 40
Iain Galloway Avatar answered Sep 30 '22 06:09

Iain Galloway