我正在使用模块级验证器:我的视图模型上的'PropertiesMustMatch',如下所示:
[PropertiesMustMatch("Password", "PasswordConfirm")]
public class HomeIndex
{
[Required]
public string Name { get; set; }
public string Password { get; set; }
public string PasswordConfirm { get; set; }
}
我注意到如果我提交没有填写Name的表单,ValidationSummary()帮助程序只返回以下错误:
- 名称字段是必需的。
但是,如果我填写名称,那么 ValidationSummary()将返回一个PropertiesMustMatch错误:
- '密码'和'密码确认'不匹配。
所以看起来首先评估属性级验证器,然后是模型级验证器。
如果他们一次全部验证我会更喜欢,ValidationSummary会返回:
- 名称字段是必需的。
- '密码'和'密码确认'不匹配。
我有什么想法可以解决这个问题吗?
我正在研究MVC 2源代码,试图确定为什么会发生这种情况。
答案 0 :(得分:0)
我发现了导致这种情况的原因,但我的“解决方案”可能会打破验证器的正常处理。请谨慎使用。
我在DefaultModelBinder的OnModelUpdated函数中找到了一个条件return语句:
protected override void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
IDataErrorInfo errorProvider = bindingContext.Model as IDataErrorInfo;
if (errorProvider != null)
{
string errorText = errorProvider.Error;
if (!String.IsNullOrEmpty(errorText))
{
bindingContext.ModelState.AddModelError(bindingContext.ModelName, errorText);
}
}
// BEGIN CONDITION
if (!IsModelValid(bindingContext))
{
return;
}
// END CONDITION
foreach (ModelValidator validator in bindingContext.ModelMetadata.GetValidators(controllerContext))
{
foreach (ModelValidationResult validationResult in validator.Validate(null))
{
bindingContext.ModelState.AddModelError(CreateSubPropertyName(bindingContext.ModelName, validationResult.MemberName), validationResult.Message);
}
}
}
如果我理解这段代码(我可能不会这样做),那么MVC团队似乎会在此时跳过模型验证器。
我已经创建了自己的自定义ModelBinder,我在其中重新运行了条件可以避免的代码:
public class CustomModelBinder : DefaultModelBinder
{
protected override void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
base.OnModelUpdated(controllerContext, bindingContext);
foreach (ModelValidator validator in bindingContext.ModelMetadata.GetValidators(controllerContext))
{
foreach (ModelValidationResult validationResult in validator.Validate(null))
{
bindingContext.ModelState.AddModelError(CreateSubPropertyName(bindingContext.ModelName, validationResult.MemberName), validationResult.Message);
}
}
}
}
这似乎解决了这个问题。