如何解决如何在Asp Net Core 3.1 Web API的派生类型列表上实现数据验证属性
说我有一个基类“动物”和一个派生类“狗”,它有一个新属性(numberOfPaws)。
如果我创建一个接受“动物”列表的控制器,那么我希望以通常的方式对我在“狗”类上标记的数据验证属性进行验证。如果超出范围,我希望它们会被拒绝。但是,尽管这适用于单个“动物”,但不适用于“动物”的列表/数组。
是否有办法使此功能适用于列表,还是必须在控制器中编写一些定制代码?
感谢您提供任何见解,请参见下面的代码。
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();
}
请注意,我正在使用JsonSubTypes(https://github.com/manuc66/JsonSubTypes),以便通过“动物”基类中的AnimalType属性正确地序列化和反序列化派生类型。
如果有人有兴趣观察这个问题,我很乐意在GitHub上放置一个最小的可重复示例。
解决方法
我最终找到了一个解决方案,这不是我所说的“干净”,但它似乎确实有效,所以我希望它可以帮助到这里的其他人,如果您找到更好的解决方案,请告诉我。
如果您创建自定义数据属性并覆盖 IsValid() 方法,那么您可以在标识派生类型的类型上使用 switch 语句来验证继承的类型属性。
将此属性放在您的基类 (Animal) 上,验证将返回标准 ASP.net 核心 validationProblemDetails 对象。
注意** 您可能不想费心在每个继承的属性上实现验证,而只是验证整个继承的对象。我试过了,但陷入了无限验证循环。
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;
}
}
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。