I want to add model validation via attributes to Web API (.NET Framework 4.7.2), but I ran into the fact that this does not work if the model is a collection.
I have a model class inherited from a dictionary. For example:
...
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;
}
}
What I've done:
- Added the
[ApiController]attribute to the controller class to activate automatic model validation on requests. - Added
System.ComponentModel.DataAnnotationsto the project. - Added validation attributes to the model fields.
This works for simple model classes, but if the model is inherited from a collection, no attribute validation occurs.
To solve this problem, I implemented the IValidatableObject interface, where I wrote the following:
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;
}
In this case, the Validate method is automatically called, where we can manually validate the attributes. However, if the attribute validation passed without validation errors, then the Validate method will be called, which, in this case, will call itself over and over again, which leads to a stack overflow exception. So I added a check to ensure that the validation has already taken place.
Thus it works, but it is not clear: why the attributes are not automatically checked if this model inherits a collection, and how to solve it?