Synchroniczny dostęp do opcji walidowanych asynchronicznie powoduje wyjątek

Począwszy od .NET 11 RC 1, synchroniczny dostęp do typu opcji, który używa tylko asynchronicznych modułów sprawdzania poprawności kończy się niepowodzeniem. Zamiast zwracać instancję opcji bez walidacji asynchronicznej, synchroniczna ścieżka tworzenia zgłasza OptionsValidationException.

Wersja wprowadzona

.NET 11 RC 1

Poprzednie zachowanie

Wcześniej w .NET 11 Preview 6 i Preview 7 IAsyncValidateOptions<TOptions> było niezależne od IValidateOptions<TOptions>. Asynchroniczne moduły sprawdzania poprawności działały tylko za pośrednictwem asynchronicznej ścieżki sprawdzania poprawności uruchamiania.

Gdy uzyskano dostęp do typu opcji walidowanego asynchronicznie przez synchroniczną ścieżkę tworzenia, taką jak IOptions<TOptions>.Value, CurrentValue, Get, IOptionsSnapshot<TOptions>.Value, Get lub Create, walidator asynchroniczny nie został uruchomiony. Ścieżka synchroniczna zwróciła niezweryfikowaną instancję opcji.

Typy, które implementowały bezpośrednio IAsyncValidateOptions<TOptions>, musiały zaimplementować tylko ValidateAsync.

Nowe zachowanie

Od .NET 11 RC 1 IAsyncValidateOptions<TOptions> dziedziczy po IValidateOptions<TOptions>, a interfejs nie jest już kontrawariantny. Asynchroniczne moduły sprawdzania poprawności uczestniczą w tej samej kolekcji modułów sprawdzania poprawności, co synchroniczne moduły sprawdzania poprawności.

Gdy uzyskasz dostęp do typu opcji zawierającego wyłącznie walidatory asynchroniczne przez synchroniczną ścieżkę tworzenia, odziedziczona metoda Validate zwraca nieudane ValidateOptionsResult. Create następnie zgłasza wartość OptionsValidationException. Komunikat o wyjątku kieruje Cię do wywołania ValidateOnStart i ukończenia uruchamiania przed synchronicznym dostępem do opcji.

Typy niestandardowe, które implementują bezpośrednio IAsyncValidateOptions<TOptions>, muszą teraz również implementować dziedziczoną metodę Validate.

Typ zmiany przełamującej

Ta zmiana jest zmianą behawioralną i może mieć wpływ na zgodność źródła. W wąskim scenariuszu, w którym binarium w wersji zapoznawczej bezpośrednio implementuje IAsyncValidateOptions<TOptions> bez ponownej kompilacji, zmiana może również wpłynąć na zgodność binarną.

Przyczyna zmiany

Asynchroniczna walidacja opcji została wprowadzona w .NET 11 Preview 6 jako mechanizm walidacji wykonywany wyłącznie podczas uruchamiania. Późniejsze prace projektowe na potrzeby walidacji po uruchomieniu ujawniły problem z poprawnością: Opcje mają także synchroniczne ścieżki tworzenia i dostępu. Walidator, który implementował wyłącznie interfejs asynchroniczny, nie mógł przejść przez te ścieżki synchroniczne, więc nieprawidłowe opcje mogły zostać zwrócone i zapisane w pamięci podręcznej, zanim uruchomiona została walidacja asynchroniczna.

Aby zamknąć tę lukę, zanim interfejs API osiągnie stabilną wersję, IAsyncValidateOptions<TOptions> pochodzi teraz z klasy IValidateOptions<TOptions>. Ujednolicony kontrakt przechowuje jedną kolekcję modułów sprawdzania poprawności, zachowuje kolejność rejestracji i sprawia, że nieobsługiwany dostęp synchroniczny kończy się niepowodzeniem z wyjątkiem z możliwością działania. Aby uzyskać więcej informacji, zobacz dotnet/runtime#131197 i zatwierdzoną propozycję interfejsu API.

W przypadku opcji, które używają tylko asynchronicznych modułów sprawdzania poprawności, wywołaj ValidateOnStart i zakończ uruchamianie hosta przed uzyskaniem dostępu do opcji synchronicznie:

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

await host.StartAsync();

Unikaj synchronicznego dostępu do opcji mających wyłącznie asynchroniczne walidatory przed zakończeniem uruchamiania. Te wskazówki dotyczą IOptions<TOptions>.Value, , IOptionsMonitor<TOptions>.CurrentValue, IOptionsMonitor<TOptions>.GetIOptionsSnapshot<TOptions>.Value, , IOptionsSnapshot<TOptions>.Geti IOptionsFactory<TOptions>.Create.

Niektóre ścieżki pozostają synchroniczne nawet po użyciu polecenia ValidateOnStart. Walidacja podczas uruchamiania nie inicjuje wartości IOptionsSnapshot<TOptions> w późniejszych zakresach, a IOptionsMonitor<TOptions> synchronicznie odtwarza opcje po zmianie konfiguracji. Jeśli te ścieżki są potrzebne do pomyślnego zweryfikowania, zachowaj co najmniej jeden synchroniczny moduł sprawdzania poprawności.

Jeśli implementujesz IAsyncValidateOptions<TOptions> bezpośrednio, dodaj dziedziczoną metodę Validate(string? name, TOptions options) i ponownie skompiluj względem platformy .NET 11. Zwróć ValidateOptionsResult.Skip, gdy walidator nie ma zastosowania, lub zwróć ValidateOptionsResult.Fail, gdy walidacja synchroniczna nie jest obsługiwana.

Jeśli Twój kod wykorzystywał usuniętą kontrawariancję in TOptions, zaktualizuj odpowiednie przypisania, rzutowania lub rejestracje.

Nie można kontrolować tego zachowania za pomocą przełącznika AppContext lub ustawienia konfiguracji.

Interfejsy API, których dotyczy problem