IRONSOFTWAREHOME

Wzorzec opcji w C#

The Options Pattern in C#

Tim Corey

10m 15s

Konfiguracja w aplikacjach .NET zwykle znajduje się w appsettings.json, zmiennych środowiskowych lub tajnych danych użytkownika. Wydobywanie tych danych konfiguracyjnych z pliku i umieszczanie ich w twoich klasach w czysty, testowalny sposób to coś, co rozwiązuje wzorzec opcji. Zamiast ręcznie czytać klucze JSON lub przekazywać surowe ciągi znaków, wiążesz sekcję konfiguracji z silnie typowaną klasą C# i pozwalasz na wstrzykiwanie zależności, aby dostarczyć ją wszędzie tam, gdzie jest potrzebna.

W swoim wideo "The Options Pattern in C#", Tim Corey wprowadza trzy warianty wzorca opcji (IOptions, IOptionsSnapshot i IOptionsMonitor), demonstruje każdy z nich w aplikacji serwerowej Blazor i pokazuje, jak dodać walidację, aby aplikacja szybko się zamknęła, gdy konfiguracja jest niekompletna lub niepoprawna. Jeśli tworzysz jakikolwiek projekt .NET, który czyta pliki konfiguracyjne i używa wstrzykiwania zależności, ten wzorzec jest podstawowy.

Przygotowanie: Model POCO i appsettings.json

[0:34 - 1:46] Tim zaczyna od aplikacji webowej Blazor (renderowanej po stronie serwera, bez interaktywności po stronie klienta), która już ma dwie części na miejscu. Pierwszym jest sekcja w appsettings.json z trzema parami klucz-wartość w sekcji CloudInfo:

// appsettings.json
{
  "CloudInfo": {
    "Storage": "https://storage.example.com",
    "Website": "https://www.example.com",
    "API": "https://api.example.com"
  }
}
C#

Druga część to zwykła klasa C# (POCO), której właściwości odzwierciedlają klucze JSON:

public class CloudInfoOptions
{
    public string Storage { get; set; }
    public string Website { get; set; }
    public string API { get; set; }
}
C#

Tim zauważa, że źródłem konfiguracji nie musi być konkretnie appsettings.json. Może to być appsettings.Development.json, secrets.json lub dowolna kombinacja. Wzorzec opcji czyta z dowolnych dostawców konfiguracji zarejestrowanych w aplikacji, a nazwy właściwości na POCO pasują do kluczy JSON z konwencji.

Rejestracja Opcji w Program.cs

[2:25 - 3:15] Podłączenie konfiguracji do iniekcji zależności wymaga dwóch wywołań metod w Program.cs:

// Register CloudInfoOptions bound to the "CloudInfo" section
builder.Services.AddOptions<CloudInfoOptions>()
    .BindConfiguration("CloudInfo");
C#

AddOptions<t>() rejestruje typ w DI. BindConfiguration("CloudInfo") informuje framework, którą część konfiguracji mapować. String "CloudInfo" odpowiada kluczowi JSON w appsettings.json. Jeśli nazwa sekcji i nazwa klasy nie pasują, argument ciągu znaków jest tym, co framework używa do znalezienia odpowiednich danych.

IOptions: Podejście Singleton

[3:15 - 5:18] Po rejestracji, Tim wprowadza konfigurację na stronę Blazor używając IOptions<CloudInfoOptions>:

@inject IOptions<CloudInfoOptions> CloudConfig

@code {
    protected override void OnInitialized()
    {
        var options = CloudConfig.Value;
        // options.Storage, options.Website, options.API are available
    }
}
C#

Kluczowy szczegół to, że IOptions<t> jest zarejestrowany jako singleton. Wartości konfiguracji są odczytywane raz, gdy aplikacja się uruchamia, i są przechowywane w pamięci podręcznej na czas trwający cały proces. Jeśli zmienisz appsettings.json podczas działania aplikacji, IOptions nie odzwierciedli tych zmian.

Dla większości aplikacji to właściwy wybór. Konfiguracja rzadko zmienia się w czasie wykonywania, a czas życia singletona oznacza brak dodatkowego obciążenia na żądanie.

IOptionsSnapshot: Odświeżanie Zasięgu

[5:18 - 6:55] Tim zamienia IOptions na IOptionsSnapshot, aby zademonstrować wariant o zasięgu:

@inject IOptionsSnapshot<CloudInfoOptions> CloudConfig
C#

IOptionsSnapshot<t> czyta konfigurację świeżo dla każdego żądania (czas życia o zasięgu). Jeśli zmodyfikujesz appsettings.json podczas działania aplikacji, kolejne żądanie internetowe przechwyci nowe wartości. Poprzednie żądanie zachowuje własną migawkę, więc nie ma niezgodności w trakcie żądania.

To jest przydatne w aplikacjach, gdzie zmiany konfiguracji muszą być wdrożone bez ponownego uruchamiania, jak przełączanie flag funkcjonalnych, aktualizowanie punktów końcowych API, czy rotacja ciągów połączeń do przechowywania. Kompromisem jest niewielki koszt na żądanie związany z ponownym odczytem konfiguracji, który jest pomijalny dla większości obciążeń.

IOptionsMonitor: Powiadomienia o Zmianach na Żywo

[6:55 - 8:34] Trzeci wariant, IOptionsMonitor<t>, idzie dalej niż przeładowanie przyrostowe. Aktywnie monitoruje zmiany w konfiguracji i może uruchamiać callbacki, gdy wartości się zmienią:

@inject IOptionsMonitor<CloudInfoOptions> CloudConfig

@code {
    protected override void OnInitialized()
    {
        // Current values
        var current = CloudConfig.CurrentValue;

        // Register a callback for live changes
        CloudConfig.OnChange(updatedOptions =>
        {
            // React to configuration changes in real time
        });
    }
}
C#

W przeciwieństwie do IOptionsSnapshot, który odświeża tylko między żądaniami, IOptionsMonitor może wykrywać zmiany podczas długotrwałej operacji. Tim wskazuje, że ma to największe znaczenie dla usług działających w tle, hubów SignalR lub dowolnego komponentu o dłuższym czasie życia niż pojedyncze żądanie HTTP.

Dodawanie Walidacji

[8:34 - 10:05] The final piece Tim covers is validation. Wzorzec opcji obsługuje zasady walidacji inline, które działają podczas pierwszego dostępu do konfiguracji:

builder.Services.AddOptions<CloudInfoOptions>()
    .BindConfiguration("CloudInfo")
    .Validate(opts =>
        !string.IsNullOrEmpty(opts.Storage) &&
        !string.IsNullOrEmpty(opts.Website) &&
        !string.IsNullOrEmpty(opts.API));
C#

Tim demonstruje przypadek niepowodzenia, usuwając wartość Storage z appsettings.json i uruchamiając aplikację. Wynik to natychmiastowy nieobsługiwany wyjątek: "CloudInfoOptions nie przeszło walidacji." Aplikacja odmawia rozpoczęcia z niekompletną konfiguracją, co jest dokładnie zachowaniem, jakiego oczekujesz. Odkrycie brakującej wartości przy starcie jest znacznie lepsze niż uderzenie w referencję z zerowym w produkcji o 2 w nocy.

W przypadku bardziej złożonych scenariuszy walidacji (kontrole między właściwościami, reguły warunkowe), można łańcuchowo połączyć wiele wywołań .Validate() lub wdrożyć IValidateOptions<t> jako dedykowaną klasę walidacji.

Podsumowanie: Trzy Interfejsy, Jeden Wzorzec

[10:05 - 10:10] Wzorzec opcji zapewnia czyste oddzielenie między magazynowaniem konfiguracji a jej konsumowaniem. IOptions obejmuje większość przypadków użycia, gdzie konfiguracja jest statyczna. IOptionsSnapshot obsługuje aplikacje, które muszą odbierać zmiany między żądaniami. IOptionsMonitor obsługuje komponenty działające długoterminowo, które potrzebują świadomości w czasie rzeczywistym na temat aktualizacji konfiguracji. A walidacja zapewnia, że twoja aplikacja wygasa głośno, gdy brakuje wymaganych wartości.

Wnioski

[10:10 - 10:15] W skrócie: zarejestruj swoją konfigurację za pomocą AddOptions<t>().BindConfiguration("SectionName") w Program.cs, wstrzyknij jeden z trzech interfejsów (IOptions, IOptionsSnapshot lub IOptionsMonitor) w zależności od wymagań dotyczących przeładowania i dodaj .Validate(), aby wychwytywać brakujące wartości przy uruchomieniu, a nie podczas działania.

Wzorzec działa w każdym typie projektu .NET: Blazor, ASP.NET Core, aplikacje konsolowe, usługi pracownicze. Rejestracja jest taka sama wszędzie.

Przykład tip: Jeśli nie jesteś pewien, który interfejs użyć, zacznij od IOptions<t>. Jest najprostszy, nie ma żadnego obciążenia na żądanie i obejmuje zdecydowaną większość przypadków, w których konfiguracja jest ustawiona przy starcie i nie zmienia się. Przejdź do IOptionsSnapshot lub IOptionsMonitor tylko wtedy, gdy masz konkretną potrzebę dla przeładowania w czasie działania.

Obejrzyj pełne wideo na jego kanale YouTube i zyskaj więcej wglądu w wzorce konfiguracyjne C#.

Earn More by Sharing What You Love

Do you create content for developers working with .NET, C#, Java, Python, or Node.js? Turn your expertise into extra income!

Let's Stay in Touch!

Join our newsletter, you’ll get exclusive access on article updates. We value your privacy

Key in blue circle

Uzyskaj natychmiast swój darmowy 30-dniowy Klucz Testowy.

Your trial license will be sent to your email address

Brak ograniczeń. 100% dostępności. Bez karty kredytowej.

bullet_checkedNie wymaga karty kredytowej ani tworzenia kontaBrak ograniczeń. 100% dostępności. Bez karty kredytowej.
  • Logo Aetna
  • Logo NASA
  • Logo GE
  • Logo Porsche
  • Logo USDA
  • Logo Qatar
Join Millions of Engineers who’ve tried IronPDF
Otrzymaj swoją Konsultację Bez Zobowiązań
Wypełnij poniższy formularz lub wyślij e-mail na sales@ironsoftware.com
Twoje dane zawsze będą utrzymywane w tajemnicy.
Zaufane przez miliony inżynierów na całym świecie
Logotypy klientów Iron Software
Otrzymaj swój darmowy Klucz Próbny na 30 dni natychmiast.
Nie wymaga karty kredytowej ani tworzenia konta