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

时间:2012-01-24 17:45:39

标签: asp.net asp.net-mvc-3

我正在使用编辑器模板和合成构建页面。我的视图模型包含自身视图模型的属性。 E.g。

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为真时才会启用子项。

我在stackoverflow上的其他地方看到过RequiredIf自定义验证属性,但只有在条件是相同视图模型的值时它才有效。我需要的东西可以检查父母,或者确实是祖先的财产。

我的临时黑客是如果复选框不为真,则清除回发时的ModelState错误。

我还必须编写一些自定义javascript,以便客户端浏览器在未勾选复选框时禁止验证。

真实的例子比这复杂得多,但希望从上面简化的例子可以清楚地知道我在追求什么。

什么是好的是父视图模型上的属性类似于

public class ParentModel
{
    public boolean SomeCheckBox { get; set; }

    [SuppressValidationIf("SomeCheckBox", false)]
    public ChildModel Child { get; set; }
}

有什么想法吗?

1 个答案:

答案 0 :(得分:6)

这个优秀的例子完美地说明了进行声明性验证的局限性,这就是数据注释的作用。

出于这个原因,我建议您使用命令式方法来处理验证规则,因为您可以处理许多场景。 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>
}

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