[英]How do I implement data validation attributes on a list of derived types in Asp Net Core 3.1 Web API
Say I have a base class 'animal' and a derived class 'dog' which has a new property (numberOfPaws).假设我有一个基础 class 'animal' 和一个派生的 class 'dog' ,它具有一个新属性(numberOfPaws)。
If I create a controller which accepts a list of 'animals' then I expect that the data validation attributes that I have labelled on my 'dog' class will be validated against in the usual way.如果我创建一个接受“动物”列表的 controller,那么我希望我在“狗”class 上标记的数据验证属性将以通常的方式进行验证。 I expect them to be rejected if out of range.
如果超出范围,我希望它们会被拒绝。 However, though this works on an individual 'animal' it does not work in a list / array of 'animals'.
但是,尽管这适用于单个“动物”,但它不适用于“动物”列表/数组。
Is there a way to make this work for a list or do I have to write some bespoke code in the controller?有没有办法让这个列表工作,或者我必须在 controller 中编写一些定制代码?
Thank you for any insights, please see the code below.感谢您的任何见解,请参阅下面的代码。
public enum AnimalType
{
Dog = 0,
Cat = 1,
}
public class Animal
{
[Required]
public string Name {get ; set;}
public AnimalType Type {get ;set;}
}
public class Dog : Animal
{
[Required]
[Range(0, 4)] // hopefully 4 <3
public int NumberOfPaws{get ; set;}
}
[HttpPost("/animal/setAnimal")]
[AllowAnonymous]
public IActionResult SetAnimal([FromBody] Animal animal)
{
_logger.LogInformation("Send a dog with 5 paws here and observe it is rejected correctly");
return Ok();
}
[HttpPost("/animal/setAnimalList")]
[AllowAnonymous]
public IActionResult SetAnimalList([FromBody] List<Animal> animalList)
{
_logger.LogInformation("Send a list of dogs here and observe that although they are correctly deseriliazed they are allowed through with 5 paws :(");
return Ok();
}
Note that i am using JsonSubTypes ( https://github.com/manuc66/JsonSubTypes ) in order to correctly serialize and deserialize the derived types via the AnimalType attribute in the 'animal' base class.请注意,我正在使用 JsonSubTypes ( https://github.com/manuc66/JsonSubTypes ) 以便通过“动物”基础 class 中的 AnimalType 属性正确序列化和反序列化派生类型。
I am happy to put a minimum repeatable example on GitHub if anyone is interested in observing this.如果有人有兴趣观察这一点,我很高兴在 GitHub 上放置一个最小可重复示例。
I eventually found a solution to this, it's not what I would call 'clean' but it does seem to work so I hope it helps others who end up here, let me know if you find a better solution.我最终找到了解决方案,这不是我所说的“干净”,但它似乎确实有效,所以我希望它可以帮助其他最终来到这里的人,如果你找到更好的解决方案,请告诉我。
If you create a custom data attribute and override the IsValid() method then you can validate the inherited types properties using a switch statement on the type which identifies your derived type.如果您创建自定义数据属性并覆盖 IsValid() 方法,那么您可以在标识派生类型的类型上使用 switch 语句来验证继承的类型属性。
Put this attribute on your base class (Animal) and the validation will work returning the standard ASP.net core validationProblemDetails object.将此属性放在您的基础 class(动物)上,验证将返回标准 ASP.net 核心验证问题详细信息 object。
Note** You might be tempted not to bother with implementing validation on each inherited property and instead just validate the whole inherited object.注意** 您可能不想对每个继承的属性进行验证,而只是验证整个继承的 object。 I tried this but got stuck in an infinite validation loop.
我试过了,但陷入了无限的验证循环。
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace Animal.Circus
{
[AttributeUsage(AttributeTargets.Class)]
public class AnimalAttribute : ValidationAttribute
{
// Not sure this is the perfect implementation of inhertited type validation but it works for now
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var animal = value as Animal;
var success = true;
var validationResults = new List<ValidationResult>();
switch (animal.Type)
{
case AnimalType.Dog:
{
var dog = (Dog)animal;
var ctx = new ValidationContext(dog);
ctx.MemberName = nameof(dog.NumberOfPaws);
success = success & Validator.TryValidateProperty(dog.NumberOfPaws, ctx, validationResults);
}
break;
case AnimalType.Animal:
// already validated by default
break;
default:
break;
}
if (!success)
{
return new ValidationResult(validationResults[0].ErrorMessage, validationResults[0].MemberNames);
}
else
{
return ValidationResult.Success;
}
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.