在父视图模型上给定特定条件的情况下,关闭本身是视图模型的特性的数据注释验证



我正在使用编辑器模板和组合构建一个页面。我的视图模型包含的属性本身就是视图模型。例如

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.MVC3NuGet,在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>
}

如果选中该复选框,则子验证器将启动并需要这两个属性。

最新更新