Проверка конфигурации NET8 (особенно с массивами) с использованием DataAnnotationsC#

Место общения программистов C#
Ответить
Anonymous
 Проверка конфигурации NET8 (особенно с массивами) с использованием DataAnnotations

Сообщение Anonymous »

Я приближаюсь к проверке конфигурации NET8 с использованием DataAnnotations, но получаю некоторые непонятные особенности поведения, особенно с массивами, которые я покажу.
appsettings.json: >

Код: Выделить всё

{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"Level": "One",
"Levels": [
"One",
"Two",
"Three",
"Four"
],
"MoreLevel":
{
"MoreLevel": "One"
},

"MoreLevels": [
{
"AnotherLevel": "One"
},
{
"MoreLevel": "Two"
},
{
"MoreLevel": "Three"
},
{
"MoreLevel": "Four"
}
]
}
LevelEnum.cs

Код: Выделить всё

    public enum LevelEnum
{
Zero,
One,
Two,
Three
}
AppOptions.cs

Код: Выделить всё

public class AppOptions
{
[Required]
public LevelEnum? Level { get; set; } = null;

[Required]
[ValidateObjectMembers]
public MoreLevelOptions? MoreLevel { get; set; } = null;

[Required]
[ValidateObjectMembers]
public List? Levels { get; set; } = null;

[Required]
[ValidateObjectMembers]
public List? MoreLevels { get; set; } = null;
}
MoreLevelOptions.cs

Код: Выделить всё

  public class MoreLevelOptions
{
[Required]
public LevelEnum? MoreLevel { get; set; } = null;
}
Program.cs

Код: Выделить всё

public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);

// Binding configuration
builder.Services
.AddOptions()
.Bind(builder.Configuration)
.ValidateDataAnnotations()
.ValidateOnStart();

// Getting 'root' configuration
AppOptions config = builder.Configuration.Get();

// Building app
var app = builder.Build();

// Runnin app
app.Run();
}
И вот что у меня не получается:
Неверное имя перечисления
Использование «Уровень»: «Один» при проверке appsetting.json работает нормально.
При использовании значения «Уровень»: «Четыре» я получаю исключение:

Код: Выделить всё

System.InvalidOperationException: 'Failed to convert configuration value at 'Level' to type 'NET8Validation.LevelEnum'.'
FormatException: Four is not a valid value for LevelEnum.
ArgumentException: Requested value 'Four' was not found.
при выполнении строки AppOptions config = builder.Configuration.Get();
Хорошо, все работает так, как ожидалось, но я получаю исключение не на .Bind(), но вместо этого, когда я пытаюсь .Get() настроить и сопоставить ее с моделью AppConfig.
ОК , я предпочитаю иметь подтверждение в момент .Bind(), но это так..
[Обязательный] атрибут
Если в appsettings.json я переключусь с

Код: Выделить всё

"Level": "One"
в

Код: Выделить всё

"NewLevel": "One"
Метод .Bind() не вызывает никаких исключений, а также строка AppOptions config = builder.Configuration.Get();.< /p>
Только при выполнении самой последней строки app.Run(); я получаю исключение:

Код: Выделить всё

'DataAnnotation validation failed for 'AppOptions' members: 'Level' with the error: 'The Level field is required.'.'
Наконец-то атрибут проверки [Required] был проверен, но в самом конце метода Main(). В некоторых случаях проверка может быть слишком поздно в это время. Как я могу проверить ее раньше, во время .Bind() или .Get()?
Почему анализ перечисления и [Обязательная] проверка выполняются в разное время в процессе запуска приложения?
Неверное имя перечисления в перечислении массив
Просмотр раздела appsettings.json

Код: Выделить всё

"Levels": [
"One",
"Two",
"Three",
"Four"
]
Я использую Four в качестве четвертого элемента массива, но, как и в первом случае, Four является неизвестным значением в перечислении LevelEnum . Я ожидаю того же исключения

Код: Выделить всё

FormatException: Four is not a valid value for LevelEnum
как и в первом случае, но здесь есть какое-то исключение, приложение запускается успешно, и внутри массива Levels я получаю 3 элемента.
Почему я получаю FormatException, как в первом случае? Почему я в итоге получаю 3 элемента в полях Level, а 1-й элемент вместо исключения просто отбрасывается?
Похоже, что валидация с полями работает по-другому и массивы, я ошибаюсь?
[Обязательно] в поле объекта (класса)
Имейте в виду, что

Код: Выделить всё

public class AppOptions
{
..
[Required]
[ValidateObjectMembers]
public MoreLevelOptions? MoreLevel { get; set; } = null;
..
}
и

Код: Выделить всё

public class MoreLevelOptions
{
[Required]
public LevelEnum? MoreLevel { get; set; } = null;
}
Поэтому требуется объект MoreLevel и поле MoreLevel.
Если в appsettings.json я переключаюсь с

Код: Выделить всё

"MoreLevel":
{
"MoreLevel": "One"
}
в

Код: Выделить всё

"MoreLevel":
{
"AnotherLevel": "One"
}
пока присутствует [ValidateObjectMembers], я получаю исключение Microsoft.Extensions.Options.OptionsValidationException во время App.Run(), но если я закомментируйте //[ValidateObjectMembers] такое же исключение больше не возникает.
Теперь мне действительно нужно декорировать поля всех объектов (классов) в модели(ах) appsettings.json, принудительно проверить все листья дерева?
Неверное имя перечисления в массиве классов
Просмотр раздела appsettings.json, сопоставленного с помощью List ? MoreLevels {получить; набор; } = null; поле

Код: Выделить всё

"MoreLevels": [
{
"AnotherLevel": "One"
},
{
"MoreLevel": "Two"
},
{
"MoreLevel": "Three"
},
{
"MoreLevel": "Four"
}
]
Я использую AnotherLevel в качестве имени поля первого элемента (оно не соответствует соответствующему полю MoreLevel [Обязательно] в MoreLevelOptions.cs) и Four
code> значение в 4-м элементе.
Я не получаю никаких исключений, ни для 1-го элемента (

Код: Выделить всё

MoreLevel
должен быть обязательным) ни для значения Four (не существующего в LevelEnum.cs).
Теперь, как я могу получить исключения для этого те же самые условия уже протестированы и работают в плоских полях (а не внутри полей объекта)?
Выводы
Мне очень трудно понять, как происходит валидация. «из коробки» работает. Моя цель должна состоять в том, чтобы украсить необходимые поля внутри классов модели параметров атрибутами [Required] и другими аннотациями данных, а также в одном месте вызвать .Bind() или .Get() методы и быть уверенным, что все проверки проверяются по всем оформленным полям моей модели(-й).
Кроме того, пользовательские Атрибуты проверки, которые я мог бы унаследовать от [ValidationAttribute], кажется, никогда не срабатывают, ни в .Bind(), ни в .Get(), ни в .Run() время.
Итак... как я могу просто заставить проверку конфигурации работать так, как я ожидаю?

Подробнее здесь: https://stackoverflow.com/questions/778 ... nnotations
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»