我正在使用编辑器模板和组合构建一个页面。我的视图模型包含的属性本身就是视图模型。例如
public class ParentModel
{
public boolean SomeCheckBox { get; set; }
public ChildModel Child { get; set; }
}
public class ChildModel
{
[Required]
public string SomeString { get; set; }
[Required]
public string SomeOtherString { get; set; }
}
我希望只有当父级上的属性SomeCheckBox为true时,数据注释验证才会在子级上生效。
我在stackoverflow的其他地方看到了RequiredIf自定义验证属性,但它只有在条件是同一视图模型的值时才有效。我需要一些可以检查父对象,或者祖先的财产的东西。
我的临时破解是,如果复选框不正确,则在回发时清除ModelState错误。
我还必须编写一些自定义javascript,这样,如果没有勾选复选框,客户端浏览器就会抑制验证。
真实的例子比这个复杂得多,但希望从上面的简化例子中可以清楚地看到我想要的是什么。
最好是父视图模型上有一个类似的属性
public class ParentModel
{
public boolean SomeCheckBox { get; set; }
[SuppressValidationIf("SomeCheckBox", false)]
public ChildModel Child { get; set; }
}
有什么想法吗?
这个优秀的例子完美地说明了进行声明性验证的局限性,声明性验证就是数据注释。
正是出于这个原因,我建议您对验证规则使用命令式方法,因为您可以处理许多场景。FluentValidation.NET是一个很好的库示例,它会让这个验证场景变得轻而易举。
让我来说明一下它如何处理这种情况:
我们首先为我们的子模型和父模型定义验证器:
public class ChildModelValidator : AbstractValidator<ChildModel>
{
public ChildModelValidator()
{
RuleFor(x => x.SomeString).NotEmpty();
RuleFor(x => x.SomeOtherString).NotEmpty();
}
}
public class ParentModelValidator : AbstractValidator<ParentModel>
{
public ParentModelValidator()
{
RuleFor(x => x.Child)
.SetValidator(new ChildModelValidator())
.When(x => x.SomeCheckBox);
}
}
注意到子验证器是如何基于父级上SomeCheckBox
属性的值包含的吗?现在你的模型看起来是这样的:
[Validator(typeof(ParentModelValidator))]
public class ParentModel
{
public bool SomeCheckBox { get; set; }
public ChildModel Child { get; set; }
}
public class ChildModel
{
public string SomeString { get; set; }
public string SomeOtherString { get; set; }
}
仅此而已。
您只需安装FluentValidation.MVC3
NuGet,在Application_Start
:中添加以下行
FluentValidationModelValidatorProvider.Configure();
现在你照常工作:
public class HomeController : Controller
{
public ActionResult Index()
{
return View(new ParentModel
{
Child = new ChildModel()
});
}
[HttpPost]
public ActionResult Index(ParentModel model)
{
return View(model);
}
}
和一个视图:
@model ParentModel
@Html.ValidationSummary(false)
@using (Html.BeginForm())
{
@Html.CheckBoxFor(x => x.SomeCheckBox)
@Html.EditorFor(x => x.Child.SomeString)
@Html.EditorFor(x => x.Child.SomeOtherString)
<button type="submit">OK</button>
}
如果选中该复选框,则子验证器将启动并需要这两个属性。