asp.net – IValidatableObject在DataAnnotations失败时触发验证
我有一个ViewModel,它有一些DataAnnotations验证,然后对于更复杂的验证实现IValidatableObject并使用Validate方法.
我期待的行为是this one:首先是所有DataAnnotations,然后,只有在没有错误的情况下,验证方法.我怎么发现这并非总是如此.我的ViewModel(一个演示版)有三个文件,一个字符串,一个十进制和一个小数?所有这三个属性都只有Required属性.对于字符串和小数?行为是预期的行为,但对于小数,当为空时,必需的验证失败(到目前为止很好),然后执行Validate方法.如果我检查属性,其值为零. 这里发生了什么?我错过了什么? 注意:我知道必须使用Required属性来检查该值是否为null.所以我希望被告知不要在不可空类型中使用Required属性(因为它不会触发),或者,某种程度上该属性理解POST值并注意该字段未被填充.在第一种情况下,属性不应该触发,并且应该触发Validate方法.在第二种情况下,属性应该触发,并且不应触发Validate方法.但我的结果是:属性触发器和Validate方法触发. 这是代码(没什么特别的): 控制器: public ActionResult Index() { return View(HomeModel.LoadHome()); } [HttpPost] public ActionResult Index(HomeViewModel viewModel) { try { if (ModelState.IsValid) { HomeModel.ProcessHome(viewModel); return RedirectToAction("Index","Result"); } } catch (ApplicationException ex) { ModelState.AddModelError(string.Empty,ex.Message); } catch (Exception ex) { ModelState.AddModelError(string.Empty,"Internal error."); } return View(viewModel); } 模型: public static HomeViewModel LoadHome() { HomeViewModel viewModel = new HomeViewModel(); viewModel.String = string.Empty; return viewModel; } public static void ProcessHome(HomeViewModel viewModel) { // Not relevant code } 视图模型: public class HomeViewModel : IValidatableObject { [Required(ErrorMessage = "Required {0}")] [Display(Name = "string")] public string String { get; set; } [Required(ErrorMessage = "Required {0}")] [Display(Name = "decimal")] public decimal Decimal { get; set; } [Required(ErrorMessage = "Required {0}")] [Display(Name = "decimal?")] public decimal? DecimalNullable { get; set; } public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) { yield return new ValidationResult("Error from Validate method"); } } 视图: @model MVCTest1.ViewModels.HomeViewModel @{ Layout = "~/Views/Shared/_Layout.cshtml"; } @using (Html.BeginForm(null,null,FormMethod.Post)) { <div> @Html.ValidationSummary() </div> <label id="lblNombre" for="Nombre">Nombre:</label> @Html.TextBoxFor(m => m.Nombre) <label id="lblDecimal" for="Decimal">Decimal:</label> @Html.TextBoxFor(m => m.Decimal) <label id="lblDecimalNullable" for="DecimalNullable">Decimal?:</label> @Html.TextBoxFor(m => m.DecimalNullable) <button type="submit" id="aceptar">Aceptar</button> <button type="submit" id="superAceptar">SuperAceptar</button> @Html.HiddenFor(m => m.Accion) } 解决方法
评论交换后的注意事项:
双方同意和expected behavior among developers是IValidatableObject的方法Validate()仅在未触发验证属性时被调用.简而言之,预期的算法就是这个(取自上一个链接): >验证属性级属性 但是,使用问题代码,即使在[必需]触发器之后也会调用Validate.这似乎是一个明显的MVC错误.据报道here. 三种可能的解决方法: >有一个解决方法here,虽然它的使用有一些陈述的问题,除了打破MVC预期的行为.通过一些更改以避免在同一字段中显示多个错误,代码如下: viewModel .Validate(new ValidationContext(viewModel,null)) .ToList() .ForEach(e => e.MemberNames.ToList().ForEach(m => { if (ModelState[m].Errors.Count == 0) ModelState.AddModelError(m,e.ErrorMessage); })); >忘记IValidatableObject并仅使用属性.它干净,直接,更好地处理本地化,并且最重要的是它可以在所有型号中重复使用.只需为您要执行的每个验证实施ValidationAttribute.您可以验证所有模型或特定属性,这取决于您.除了默认可用的属性(DataType,Regex,Required和所有这些东西)之外,还有几个具有最常用验证的库.实现“失踪者”的是FluentValidation. 评论前回答: 首先,我从头开始创建了一个新项目,只提供了您提供的代码.它永远不会同时触发数据注释和Validate方法. 无论如何,知道这一点, 根据设计,MVC3将[Required]属性添加到非可空值类型,如int,DateTime或yes,decimal.因此,即使您从该小数中删除了所需的属性,它也就像它在那里一样. 这是错误的(或不是),但它的设计方式是有争议的. 在你的例子中: >如果[Required]存在且没有给出值,则’DataAnnotation’触发.从我的观点来看,完全可以理解 看来,这种行为可能会在Application_Start方法中被关闭: DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false; 我猜这个属性的名字是不言自明的. 无论如何,我不明白为什么你想让用户输入不需要的东西,不要让那个属性可以为空.如果它是null,那么检查它是你的工作,如果在验证之前你不想在控制器内做空. public ActionResult Index(HomeViewModel viewModel) { // Complete values that the user may have // not filled (all not-required / nullables) if (viewModel.Decimal == null) { viewModel.Decimal = 0m; } // Now I can validate the model if (ModelState.IsValid) { HomeModel.ProcessHome(viewModel); return RedirectToAction("Ok"); } } 您觉得这种方法有什么不对,或者不应该这样? (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- ViewState在ASP.NET MVC中是否相关?
- asp.net-mvc – Asp.net MVC 3路由区域失败
- 三步快速解决dll冲突问题
- asp.net-mvc-3 – 如何创建通用的MVC3编辑器模板?
- .net – MVC,ViewModels和Validation
- asp.net – Visual Studio在Aspx文件中缺少扩展/折叠按钮
- .net – 制作类似TinyURL.com的简短网址
- asp.net-mvc – ASP.NET MVC:很多路由 – >总是只有一个控
- asp.net-mvc – 在ASP.NET MVC的查询字符串中使用DateTime创
- asp.net – Response.Redirect()不起作用