为什么自动属性验证不适用于继承集合的模型?

问题描述

我想通过属性将模型验证添加到Web API( .NET Framework 4.7.2 ),但是我遇到这样的事实,即,如果模型是集合,这将不起作用。

我有一个从字典继承的模型类。例如:

...
using System.ComponentModel.DataAnnotations;
...

public class MyModel : Dictionary<string,string>
{
    [StringLength(100)]
    public string SomeField
    {
        get => TryGetValue("someField",out var value) ? value : null;
        set => this["someField"] = value;
    }
}

我所做的事情:

  1. 在控制器类中添加[ApiController]属性,以根据请求激活自动模型验证。
  2. 已将System.ComponentModel.DataAnnotations添加到项目中。
  3. 向模型字段添加了验证属性

这适用于简单的模型类,但是如果模型是从集合继承的,则不会发生属性验证。

解决此问题,我实现了IValidatableObject接口,在其中编写了以下内容

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
    const string validationStatusFieldName = "alreadyValidated";
    if (validationContext.Items.TryGetValue(validationStatusFieldName,out var alreadyValidated) && (bool) alreadyValidated)
        return Enumerable.Empty<ValidationResult>();
    validationContext.Items[validationStatusFieldName] = true;

    var validationResults = new List<ValidationResult>();
    var isValid = Validator.TryValidateObject(validationContext.ObjectInstance,validationContext,validationResults,true);
    return isValid
        ? Enumerable.Empty<ValidationResult>()
        : validationResults;
}

在这种情况下,将自动调用Validate方法,在此我们可以手动验证属性。但是,如果通过了属性验证而没有验证错误,则将调用Validate方法在这种情况下,将反复调用自身,这将导致堆栈溢出异常。因此,我添加一个检查以确保验证已经进行。

这样就可以了,但是还不清楚:为什么这个模型继承了一个集合,为什么不自动检查属性,以及如何解决呢?

解决方法

验证者有一个condition,他可以在其中精确选择验证对象的方式。首先检查模型是否为集合,然后检查模型的每个元素。并且由于此集合存储没有验证约束的字符串,因此验证没有任何注释。如果通过属性进行字段验证没有问题,那么将调用Validate方法,这将发生。

如何解决此问题:

  • 实现IValidatableObject接口,并在Validate方法中尝试验证当前实例,并记住退出无限递归。 (已在问题中完成)

  • 为模型类创建一个自定义验证属性(继承自ValidationAttribute),该类将搜索具有验证属性的属性并独立地对其进行验证。