如何禁用MVC 4模型验证?

时间:2012-10-29 13:22:39

标签: c# asp.net-mvc model-validation

我正在研究一个在mvc 4上编写的项目,该项目有几个类似向导的行为实例 - 几个视图链通过相同的半填充模型。从第二个视图控件开始最初显示为无效(这是逻辑 - 模型,传递给控制器​​方法具有相应的属性为空)。目前 ModelState.Clear(); 使用了解决方案,但是将模型作为参数放入每个方法看起来很难看。与Disable Model Validation in Asp.Net MVC

中的方法相同
ModelBinders.Binders[typeof(MyModelType)] = new NonValidatingModelBinder();

项目有太多(超过100个)模型类来手动注册每个模型类。

是否有更简单的方法(可能是.config键)完全关闭模型验证?

4 个答案:

答案 0 :(得分:8)

我不知道这可行,但你试试这个(bootstrap代码或global.asax)

ModelValidatorProviders.Providers.Clear();

答案 1 :(得分:4)

我知道它并没有真正回答你的问题,只是为了扩展我的评论: -

听起来你有类似的东西: -

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

当您发布第1步时遇到问题,因为用户尚未输入Bar的值,因此存在ModelStateError

我首选的解决方案,不是试图弄乱你的持久性模型的验证,而是将View实现与Model实现分离,每个Wizard步骤都有一个ViewModel,例如: -

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

您的控制器操作类似于: -

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

您的StepOne视图类似于: -

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

您的StepTwo视图类似于: -

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

与仅关闭模型验证相比,主要优势在于您可以将当前步骤的验证要求放在ViewModel上 - 您可以确保第一步中的所有值都有效,然后再继续执行第二步。

  • 如果你想要一个更RESTful的方法(你的控制器不关心数据是来自向导式的视图),另一个流行的解决方案是将每个步骤包装在< div>中。客户端并使用javascript在用户进展时隐藏/显示它们。

  • 如果您的模型需要在步骤之间保持不变,那么您需要考虑模型上的ValidationAttributes及其含义。如果您使用User.DateOfBirthRequired进行了注释,但是您需要能够在填充它的步骤之前保留它,那么事实上User.DateOfBirth 不是 required(例如,EF CodeFirst不能使列NOT NULL,因为我们需要能够在此期间保持空值)。您需要进行一些条件验证(例如IValidatableObjectMvcFoolproofFluent Validation),以便稍后验证您的完整模型。

答案 2 :(得分:2)

我不知道web.config中的所有选项或类似的东西。但你可以用这个:

Assembly.GetExecutingAssembly()
   .GetTypes()
   .Where(t => t.IsClass && t.Namespace == "Your.Name.Space")
   .ToList()
   .ForEach(t => ModelBinders.Binders[t] = new NonValidatingModelBinder());

或者

typeof(MyModelType)
   .Assembly
   .GetTypes()
   .Where(t => t.IsClass && t.Namespace == "Your.Name.Space")
   .ToList()
   .ForEach(t => ModelBinders.Binders[t] = new NonValidatingModelBinder());

或删除&& t.Namespace == "Your.Name.Space"部分,以便将程序集中的所有类添加到NonValidatingModelBinder。

不要忘记添加using System.Linq;

答案 3 :(得分:0)

@{
HtmlHelper.ClientValidationEnabled = false;
}