在 C# 中验证列表

mko*_*man 3 c# validation data-annotations

我们正在使用DataAnnotations来验证我们的模型。

我们模型的一个非常简化的版本是:

public class Model
{
    public List<Thing> Things;
}

public class Thing
{
    [Required]
    public string Name {get;set;}
}
Run Code Online (Sandbox Code Playgroud)

现在,有趣的是,如果我创建一个Thing没有名称的并将其添加到模型中,我希望验证失败,但它通过了(震惊!)。

var model = new Model ();
var invalidThing = new Thing (); // No name would fail validation
model.Things.Add(invalidThing );

var validationContext = new ValidationContext(model);
var validationResults = new List<ValidationResult>();
var isValid = Validator.TryValidateObject(model, validationContext, validationResults, true);

Assert.False (isValid);  // This fails!
Run Code Online (Sandbox Code Playgroud)

认为这样做的原因是当您验证模型时,它会验证每个属性,但如果它是一个集合,则不会验证属性中的项目。Things是一个没有验证的属性,所以它通过了(尽管它包含无效项目)。

我们如何确保验证也验证集合属性中的项目?我可以使用一些开箱即用的验证器吗?

mko*_*man 16

我通过为集合创建一个自定义验证器来检查每个项目的验证来解决这个问题。简化的代码如下所示:

public class ValidateEachItemAttribute : ValidationAttribute
{
    protected readonly List<ValidationResult> validationResults = new List<ValidationResult>();

    public override bool IsValid(object value)
    {
        var list = value as IEnumerable;
        if (list == null) return true;

        var isValid = true;

        foreach (var item in list)
        {
            var validationContext = new ValidationContext(item);
            var isItemValid = Validator.TryValidateObject(item, validationContext, validationResults, true);
            isValid &= isItemValid;
        }
        return isValid;
    }

    // I have ommitted error message formatting
}
Run Code Online (Sandbox Code Playgroud)

现在以这种方式装饰模型将按预期工作:

public class Model
{
    [ValidateEachItem]
    public List<Thing> Things;
}
Run Code Online (Sandbox Code Playgroud)

  • 不再是有效的答案,因为如文档中所述:不应在派生类中重写 bool IsValid(object) 方法。相反,应该实现 IsValid(object, ValidationContext)。 (2认同)