使用IValidatableObject时,必需属性不出现在错误列表中

时间:2014-02-06 19:09:32

标签: c# asp.net-mvc validation

我的某个类在某些属性上有[Required]个装饰,但也需要一些自定义验证,所以它使用IValidatableObject

public class ModelCourse : IValidatableObject
{
    //some other code...

    [DisplayName("Course Name")]
    [Required]
    [StringLength(100, MinimumLength=1)]
    public String name { get; set; }

    //more code...

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (courseGradeLevels == null || courseGradeLevels.Count < 1)
        {
            yield return new ValidationResult("You must select at least one grade level.");
        }
        if ((courseLength == CourseLength.Other) && string.IsNullOrEmpty(courseLengthDescription))
        {
            yield return new ValidationResult("Course Length Description is Required if Length is Other.");
        }
    }
}

验证

        //course is one of a few child objects in this class
        bool dbDetailsValid = TryValidateModel(dbDetails);

        ViewData["courseValid"] = !ModelState.ContainsKey("course");

        foreach(KeyValuePair<string, ModelState> pair in ModelState.Where(x => x.Value.Errors.Count > 0))
        {
            ViewData[pair.Key + "ErrorList"] = pair.Value.Errors.ToList();
        }

运行此代码时,name的空白字符串不会导致ModelState出错。自定义验证逻辑按预期工作,但我不明白为什么TryValidateModel没有接受装饰...是我手动检查每个必填字段的唯一选择?

1 个答案:

答案 0 :(得分:1)

感谢@nick nieslanik指点我Understanding ValidationContext in DataAnnotations,我有答案。

在我的自定义验证方法中,我使用反射来遍历每个属性,并在每个属性上调用TryValidateProperty,如果它不验证则将其添加到结果中:

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        List<ValidationResult> results = new List<ValidationResult>();
        foreach (PropertyInfo property in this.GetType().GetProperties())
        {
            Validator.TryValidateProperty(property.GetValue(this), new ValidationContext(this, null, null) { MemberName = property.Name }, results);
            if (results.Count > 0)
            {
                foreach (ValidationResult err in results)
                {
                    yield return new ValidationResult(err.ErrorMessage);
                }
                results.Clear();
            }
        }
        //the rest of the validation happens here...
    }