簡體   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

假設我有一個基礎 class 'animal' 和一個派生的 class 'dog' ,它具有一個新屬性(numberOfPaws)。

如果我創建一個接受“動物”列表的 controller,那么我希望我在“狗”class 上標記的數據驗證屬性將以通常的方式進行驗證。 如果超出范圍,我希望它們會被拒絕。 但是,盡管這適用於單個“動物”,但它不適用於“動物”列表/數組。

有沒有辦法讓這個列表工作,或者我必須在 controller 中編寫一些定制代碼?

感謝您的任何見解,請參閱下面的代碼。

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 ) 以便通過“動物”基礎 class 中的 AnimalType 屬性正確序列化和反序列化派生類型。

如果有人有興趣觀察這一點,我很高興在 GitHub 上放置一個最小可重復示例。

我最終找到了解決方案,這不是我所說的“干凈”,但它似乎確實有效,所以我希望它可以幫助其他最終來到這里的人,如果你找到更好的解決方案,請告訴我。


如果您創建自定義數據屬性並覆蓋 IsValid() 方法,那么您可以在標識派生類型的類型上使用 switch 語句來驗證繼承的類型屬性。

將此屬性放在您的基礎 class(動物)上,驗證將返回標准 ASP.net 核心驗證問題詳細信息 object。

注意** 您可能不想對每個繼承的屬性進行驗證,而只是驗證整個繼承的 object。 我試過了,但陷入了無限的驗證循環。

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM