6

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

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

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

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

4

4 回答 4

8

我不知道这是否可行,但您尝试过吗(引导代码或 global.asax)

ModelValidatorProviders.Providers.Clear();
于 2012-10-29T13:29:28.280 回答
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 实现分离,每个向导步骤都有一个 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 不需要(例如,EF CodeFirst 不能使列 NOT NULL,因为我们需要能够持久化同时为空值)。您需要进行一些条件验证(例如IValidatableObjectMvcFoolproofFluent Validation),以便稍后验证您的完整模型。

于 2012-10-29T14:08:05.193 回答
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;

于 2012-10-29T13:27:08.037 回答
0
@{
HtmlHelper.ClientValidationEnabled = false;
}
于 2013-12-05T11:24:57.207 回答