简体   繁体   English

如何在 Asp Net Core 3.1 Web API 中的派生类型列表上实现数据验证属性

[英]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.

相关问题 我需要在 ASP.Net 核心的验证属性中返回自定义验证结果(响应) Web API - I need to return customized validation result (response) in validation attributes in ASP.Net core Web API 如何使用 ASP.NET Core 3.1 MVC 和 EF Core 对唯一字段使用数据验证注释? - How do use data validation annotation for unique fields with ASP.NET Core 3.1 MVC and EF Core? 如何在 ASP.NET Core 中实现复选框列表? - How do I implement a checkbox list in ASP.NET Core? 在 ASP.NET Core Web API 3.1+ 中继承路由属性 - Inheriting route attributes in ASP.NET Core Web API 3.1+ 如何在 asp.net 核心 3.1 mvc web 应用程序中将日志保存到数据库? - How do I save logs to database in asp.net core 3.1 mvc web application? "ASP.NET Core 3.1:Web Api:相同的发布方法:多种类型的 Json 对象" - ASP.NET Core 3.1: Web Api: Same Post Method: Multiple types of Json Objects 如何在 asp net core 3.1 中配置身份? - How do I configure Identity in asp net core 3.1? 如何在 .NET Core 3.1 中调用 WCF web 服务? - How do I call a WCF web service in .NET Core 3.1? ASP.NET 核心 Web API - 如何将属性组合作为原始数据存储到另一个 ZA559B08606892EE78C 的单个列中 - ASP.NET Core Web API - How to store combination of attributes as raw data into a single column of another Model 如何在 ASP.NET Core 中实现自定义模型验证? - How do I implement custom model validation in ASP.NET Core?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM