Синхронный доступ к параметрам, асинхронно прошедшим проверку, вызывает исключение

Начиная с .NET 11 RC 1, синхронный доступ к типу параметров, использующему только асинхронные валидаторы, немедленно завершается ошибкой. Вместо возврата экземпляра параметров без асинхронной валидации при синхронном создании генерируется исключение OptionsValidationException.

Представленная версия

.NET 11 RC 1

Предыдущее поведение

Ранее в .NET 11 Preview 6 и Preview 7 IAsyncValidateOptions<TOptions> не зависел от IValidateOptions<TOptions>. Асинхронные валидаторы запускались только через асинхронный путь валидации при запуске.

Если вы обращались к типу параметров с асинхронной проверкой через синхронный способ создания, например IOptions<TOptions>.Value, CurrentValue, Get, Get, IOptionsSnapshot<TOptions>.Value или Create, асинхронный валидатор не запускался. Синхронный путь вернул экземпляр непроверенных параметров.

Типам, которые напрямую реализовывали IAsyncValidateOptions<TOptions>, нужно было реализовать только ValidateAsync.

Новое поведение

Начиная с .NET 11 RC 1, IAsyncValidateOptions<TOptions> наследуется от IValidateOptions<TOptions>и интерфейс больше не является контравариантным. Асинхронные проверяющие элементы участвуют в той же коллекции проверяющих элементов, что и синхронные проверяющие элементы.

Если обратиться к типу параметров только с асинхронными валидаторами через синхронный путь создания, унаследованный метод Validate возвращает объект ValidateOptionsResult с ошибкой. Create затем вызывает OptionsValidationException. Сообщение об исключении указывает, что необходимо вызвать ValidateOnStart и завершить запуск, прежде чем синхронно обращаться к параметрам.

Пользовательские типы, непосредственно реализующие IAsyncValidateOptions<TOptions>, теперь также должны реализовывать унаследованный метод Validate.

Тип разрушающего изменения

Это изменение является изменением поведения и может повлиять на совместимость источников. В узком сценарии, где двоичный файл предварительной версии напрямую реализуется IAsyncValidateOptions<TOptions> без повторной компиляции, это изменение также может повлиять на совместимость двоичных файлов.

Причина изменения

Асинхронная проверка параметров была представлена в предварительной версии 6 .NET 11 как механизм проверки, используемый только при запуске. В ходе последующей проектной работы для валидации после запуска был выявлен пробел в обеспечении корректности: у опций также есть синхронные пути создания и доступа. Валидатор, реализующий только асинхронный интерфейс, не мог обрабатываться по этим синхронным путям выполнения, поэтому некорректные параметры могли быть возвращены и кэшированы до того, как выполнялась асинхронная проверка.

Чтобы устранить это несоответствие до выхода стабильной версии API, IAsyncValidateOptions<TOptions> теперь является производным от IValidateOptions<TOptions>. Единый контракт сохраняет одну коллекцию проверяющего элемента, сохраняет порядок регистрации и делает неподдерживаемый синхронный доступ сбоем с допустимым исключением. Дополнительные сведения см. в статье dotnet/runtime#131197 и утвержденном предложении API.

Для параметров, использующих только асинхронные валидаторы, вызовите ValidateOnStart и дождитесь завершения запуска узла, прежде чем обращаться к параметрам синхронно:

services.AddOptions<MyOptions>()
    .Configure(o => o.Value = 42)
    .ValidateAsync(o => Task.FromResult(o.Value > 0), "Value must be positive.")
    .ValidateOnStart();

await host.StartAsync();

Избегайте синхронного доступа к параметрам, для которых используются только асинхронные валидаторы, до завершения запуска. Это руководство относится к IOptions<TOptions>.Value, , IOptionsMonitor<TOptions>.CurrentValue, IOptionsMonitor<TOptions>.Get, IOptionsSnapshot<TOptions>.GetIOptionsSnapshot<TOptions>.Valueи IOptionsFactory<TOptions>.Create.

Некоторые пути остаются синхронными даже после использования ValidateOnStart. Проверка запуска не задает IOptionsSnapshot<TOptions> начальные значения для последующих областей и IOptionsMonitor<TOptions> создает параметры синхронно после изменения конфигурации. Если вам нужно, чтобы эти пути успешно проходили проверку, оставьте как минимум один синхронный валидатор.

Если вы реализуете IAsyncValidateOptions<TOptions> напрямую, добавьте унаследованный Validate(string? name, TOptions options) метод и перекомпилируйте его в .NET 11. Возвращайте ValidateOptionsResult.Skip, если валидатор неприменим, или ValidateOptionsResult.Fail, если синхронная проверка не поддерживается.

Если в вашем коде использовалась удалённая возможность контравариантности in TOptions, обновите затронутые присваивания, приведения типов или регистрации.

Вы не можете управлять этим поведением с помощью параметра appContext или параметра конфигурации.

Затронутые API