在ASP.NET MVC3中validation表单时,是否有任何方法可以忽略某些属性(在POCO上)?

我有一个注册向导用于新用户注册。 当我尝试转到第二页时,我收到validation错误,因为我的User对象尚未完全填充。 有什么办法可以告诉每个ActionMethod在检查ModelState.IsValid检查时忽略一些属性吗?

例如。 (简体,pseduo代码)

 public class User { [Required] public string Name; // Asked on page 1. [Required] public int Age; // Asked on page 1. [Required] public string Avatar; // Asked on Page 2. } 

它抱怨说阿凡达是必需的/不能为空。 但我没有机会要求用户填写此内容,直到下一页。

在第1页中是否可以要求忽略此检查?

您可以使用绑定属性: http : //ittecture.wordpress.com/2009/05/01/tip-of-the-day-199-asp-net-mvc-defining-model-binding-explicitly/

更好的选择是使用ViewModels。

http://weblogs.asp.net/shijuvarghese/archive/2010/02/01/view-model-pattern-and-automapper-in-asp-net-mvc-applications.aspx

在操作中,只删除尚未检查的项目的错误。 然后,这使您的模型对已检查的项目有效

 foreach (var error in ModelState["Avatar"].Errors) { ModelState["Avatar"].Errors.Remove(error); } 

要么

 ModelState["Avatar"].Errors.Clear(); 

这在史蒂夫桑德森的asp.net mvc 2书,第486页中讨论过。

创建一个inheritance自ActionFilterAttribute的自定义属性ValidateIncomingValuesOnlyAttribute,并将其应用于控制器类。

覆盖OnActionExecuting方法:

 public override void OnActionExecuting(ActionExecutingContext filterContext) { var modelState = filterContext.Controller.ViewData.ModelState; var incomingValues = filterContext.Controller.ValueProvider; var keys = modelState.Keys.Where(x => !incomingValues.ContainsPrefix(x)); foreach(var key in keys) { modelState[key].Errors.Clear(); } } 

这样,您只需validation与向导中每个步骤相关的数据。 然后,您需要一个没有数据输入的确认页面,以将validation的数据发送到服务器。

但最重要的是,阅读史蒂夫桑德森的书,它为这个和你的另一个问题提供了一个有效的解决方案。

附录:

如果您决定映射到viewmodel而不是上面的内容,请小心,因为您将要么:

一个。 不使用validationdataannotation属性装饰viewmodel属性,在这种情况下,只有在用户填写完整个向导并尝试提交到数据库后才会进行validation。 从用户的角度来看,这将非常简单……

湾 否则,您仍然必须使用S Sanderson描述的技术,即清除与当前步骤中的字段无关的任何validation错误。

我没有看到接受的答案是回答问题。

要忽略ModelState中的属性,这是最简单的代码。

 if (ModelState["PropertyName"] != null) ModelState["PropertyName"].Errors.Clear(); 

我只是弄乱了validation表单和ModelState ,发现了一个非常简单的解决方案,无需编写任何新方法,覆盖等。

 ModelState.Where(m => m.Key == "Avatar").FirstOrDefault().Value.Errors.Clear(); // At this point ModeState will have an error for that Key, // by applying Clear it remove the error so modelstate becomes valid again if (!ModelState.IsValid) { return View("User", model); } else { try { // do something } catch { TempData["errorMessage"] = "something went wrong"; } } 

那么IgnoreModelErrors自定义类怎么样?

http://mrbigglesworth79.blogspot.in/2011/12/partial-validation-with-data.html


inheritance自ActionFilterAttribute类,并清除OnActionExecuting中的错误[基于匹配的名称或正则表达式],如上面的链接所示。 这将更清洁。

与回发数据完全匹配的ViewModel通常是推荐的技术,因为它是非常可预测的,并且您可以获得强类型,脚手架等的所有好处。另一方面,使用BindAttribute可能需要您获取属性不会重新发布帐户,并且在更改属性名称但未绑定BindAttribute Include或Exclude字符串时,可能会在运行时导致静默失败。 避免使用validation属性在MVC中有许多缺点,需要用其他validation技术(如IValidatableObject或FluentValidation)替换。

尽管ViewModel具有所有优点以及BindAttribute附带的警告,但有时仍然可以优先使用BindAttribute并部分发布到模型/视图模型。 此ActionFilterAttribute涵盖了这种确切的情况。 这需要代码@awrigley进一步引用,但不是基于ValueProvider清除错误,而是根据BindAttribute的使用(例如Include和Exclude)清除错误。 此属性可以安全地添加到GlobalFilterCollection中,因为它不会在未应用BindAttribute时更改MVCvalidation的行为。 请注意:我没有大量使用它,但它适用于我的基本情况。

 using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; using System.Web.Mvc; ///  /// When the BindAttribute is in use, validation errors only show for values that /// are included or not excluded. ///  public class ValidateBindableValuesOnlyAttributes : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext filterContext) { var modelState = filterContext.Controller.ViewData.ModelState; var includedProperties = filterContext.ActionDescriptor.GetParameters() .SelectMany(o => o.BindingInfo.Include.Select(name => (string.IsNullOrWhiteSpace(o.BindingInfo.Prefix) ? "" : o.BindingInfo.Prefix + ".") + name)); var excludedProperties = filterContext.ActionDescriptor.GetParameters() .SelectMany(o => o.BindingInfo.Exclude.Select(name => (string.IsNullOrWhiteSpace(o.BindingInfo.Prefix) ? "" : o.BindingInfo.Prefix + ".") + name)); var ignoreTheseProperties = new List>(); if (includedProperties.Any()) { ignoreTheseProperties.AddRange(modelState.Where(k => !includedProperties.Any(name => Regex.IsMatch(k.Key, "^" + Regex.Escape(name) + @"(\.|\[|$)")))); } ignoreTheseProperties.AddRange(modelState.Where(k => excludedProperties.Any(name => Regex.IsMatch(k.Key, "^" + Regex.Escape(name) + @"(\.|\[|$)")))); foreach (var item in ignoreTheseProperties) { item.Value.Errors.Clear(); } } } 

我有一个不应该被validation的参考实体。

在操作开始时将其从validation中删除:

 [HttpPost] public async Task Post([FromBody] Contact contact) { var skipped = ModelState.Keys.Where(key => key.StartsWith(nameof(Contact.Portfolios))); foreach (var key in skipped) ModelState.Remove(key); //ModelState doesn't include anything about Portfolios which we're not concerned with if (!ModelState.IsValid) return BadRequest(ModelState); //Rest of action }