127 lines
7.5 KiB
Markdown
127 lines
7.5 KiB
Markdown
## Wstęp merytoryczny: Ewolucja zarządzania konfiguracją w ekosystemie .NET
|
||
|
||
W procesie transformacji aplikacji desktopowych z **.NET Framework 4.8** do nowoczesnego środowiska **.NET 10**, zmianie ulega nie tylko sposób renderowania interfejsu, ale również mechanika zarządzania ustawieniami aplikacji. W starym modelu architektonicznym parametry konfiguracyjne przechowywano w ciężkich, płaskich plikach XML (`App.config` dla WPF/WinForms lub `Web.config`), z których odczytywano je najczęściej za pomocą statycznej klasy `ConfigurationManager`.
|
||
|
||
W ASP.NET Core oraz nowym modelu uruchomieniowym odpowiedzialność za konfigurację przejmuje **Generic Host** (Host Ogólny). Infrastruktura Hosta domyślnie ładuje i agreguje ustawienia z wielu źródeł, w tym przede wszystkim z nowoczesnego, hierarchicznego pliku `appsettings.json`. Podejście to całkowicie rezygnuje ze statycznego, globalnego dostępu do stanu aplikacji na rzecz wbudowanego wstrzykiwania zależności (DI).
|
||
|
||
## Analiza Porównawcza: Zarządzanie ustawieniami (Desktop 4.8 vs Web .NET 10)
|
||
|
||
| **Koncepcja Desktop (.NET 4.8)** | **Odpowiednik w .NET 10 (Generic Host)** | **Charakter zmiany architektonicznej** |
|
||
| --- | --- | --- |
|
||
| **Plik `App.config` / `Web.config` (XML)** | **Plik `appsettings.json` (JSON)** | Przejście z płaskich struktur XML z atrybutami, na elastyczne i czytelne struktury hierarchiczne (zagnieżdżone obiekty JSON). |
|
||
| **Statyczna klasa `ConfigurationManager`** | **Interfejs `IConfiguration` i Kontener DI** | Wyeliminowanie wzorca Service Locator oraz globalnego stanu na rzecz wstrzykiwania zależności, ściśle zarządzanego przez Generic Host. |
|
||
| **Brak wbudowanych profili środowiskowych** | **`appsettings.Development.json` / Zmienne Środowiskowe** | Host automatycznie podmienia wartości konfiguracji bazując na aktywnym środowisku (np. Development, Production) bez potrzeby stosowania transformacji XML. |
|
||
| **Ręczne rzutowanie typów (`int.Parse`)** | **Options Pattern (`IOptions<T>`)** | Automatyczne mapowanie sekcji plików JSON na silnie typowane klasy (POCO), wstrzykiwane bezpośrednio do logiki biznesowej. |
|
||
|
||
## Głębokie Nurkowanie (Deep Dive): Integracja konfiguracji z Generic Host
|
||
|
||
W architekturze ASP.NET Core, plik `appsettings.json` nie jest samodzielnym bytem, lecz integralną częścią procesu budowania Hosta. Gdy w pliku startowym wywołujemy konstrukcję `WebApplication.CreateBuilder(args)`, Generic Host pod spodem konfiguruje całą infrastrukturę ładowania ustawień.
|
||
|
||
Proces ten odbywa się warstwowo. Host odczytuje konfigurację z określonego łańcucha dostawców (Configuration Providers) w ustalonej kolejności:
|
||
1. Podstawowy plik `appsettings.json`.
|
||
2. Plik środowiskowy, np. `appsettings.Development.json` lub `appsettings.Production.json`.
|
||
3. Zmienne środowiskowe (Environment Variables) systemu operacyjnego, które zawsze nadpisują wartości z plików JSON.
|
||
4. Argumenty wiersza poleceń.
|
||
|
||
Dzięki temu system jest naturalnie przystosowany do orkiestracji kontenerów (np. Docker, Kubernetes), w których zmienne środowiskowe sterują zachowaniem Hosta bez konieczności re-kompilacji aplikacji czy podmiany plików konfiguracyjnych.
|
||
|
||
## Architektura systemowa: Wzorzec Opcji (Options Pattern)
|
||
|
||
Bezpośrednie używanie interfejsu `IConfiguration` w klasach biznesowych, polegające na odpytywaniu go ciągami znaków (np. `config["Smtp:Port"]`), jest w nowoczesnym .NET antywzorcem prowadzącym do tzw. *magic strings*.
|
||
|
||
Zamiast tego, framework promuje użycie **Options Pattern**. Architektura ta polega na stworzeniu klasy C# idealnie odzwierciedlającej strukturę wycinka pliku `appsettings.json`. Następnie, za pomocą kontenera usług Hosta (DI), wiążemy (bindujemy) sekcję pliku JSON z tą klasą. Wymusza to silne typowanie konfiguracji w całym rurociągu żądań HTTP i eliminuje rozproszenie danych aplikacyjnych.
|
||
|
||
## Dobre Praktyki i Antywzorce
|
||
|
||
Proces migracji wymusza rewizję dawnych nawyków konfiguracji środowisk deweloperskich i produkcyjnych:
|
||
|
||
* **Antywzorzec: Przechowywanie tajemnic w `appsettings.json`.** Przechowywanie kluczy do zewnętrznych API, haseł do bazy danych czy certyfikatów produkcyjnych jawnym tekstem w konfiguracji zapisanej w repozytorium źródłowym.
|
||
* **Dobra praktyka:** Parametry połączeń (Connection Strings) na maszynie programisty należy umieszczać w specjalnym lokalnym mechanizmie wbudowanym w Hosta – *Secret Manager* (User Secrets). Na docelowym środowisku produkcyjnym korzystamy natomiast z usług do bezpiecznego przechowywania tajemnic, np. **Azure Key Vault**. Generic Host automatycznie podepnie te źródła jako bezpieczne nadpisania dla pliku konfiguracyjnego.
|
||
|
||
## Laboratorium kodu: Konfiguracja i Wzorzec Opcji
|
||
|
||
Poniższe bloki demonstrują prawidłową konfigurację w .NET 10, która na etapie startu Hosta wiąże właściwości z sekcją pliku JSON, wstrzykując je jako silnie typowaną klasę do logiki aplikacji.
|
||
|
||
**1. Plik `appsettings.json`:**
|
||
Hierarchiczna struktura zastępująca zawiłe bloki znane z dawnego `<appSettings>`.
|
||
|
||
```json
|
||
{
|
||
"Logging": {
|
||
"LogLevel": {
|
||
"Default": "Information",
|
||
"Microsoft.AspNetCore": "Warning"
|
||
}
|
||
},
|
||
"SystemSettings": {
|
||
"FeatureToggle": true,
|
||
"MaxRetryAttempts": 3
|
||
}
|
||
}
|
||
```
|
||
|
||
**2. Klasa Opcji (POCO):**
|
||
Obiekt modelujący ustawienia biznesowe.
|
||
|
||
```csharp
|
||
namespace ModernApp.Configuration;
|
||
|
||
public class SystemSettingsOptions
|
||
{
|
||
// Konwencja nazewnicza ściśle odpowiada polom z pliku JSON
|
||
public bool FeatureToggle { get; set; }
|
||
public int MaxRetryAttempts { get; set; }
|
||
}
|
||
```
|
||
|
||
**3. Inicjalizacja Hosta (`Program.cs`):**
|
||
Rejestracja opcji bezpośrednio z poziomu kontenera DI budowniczego. Wzorzec ten izoluje `IConfiguration` tylko do momentu startu aplikacji.
|
||
|
||
```csharp
|
||
using ModernApp.Configuration;
|
||
|
||
var builder = WebApplication.CreateBuilder(args);
|
||
|
||
// Rejestracja sekcji JSON i wstrzyknięcie jako IOptions<SystemSettingsOptions>
|
||
builder.Services.Configure<SystemSettingsOptions>(
|
||
builder.Configuration.GetSection("SystemSettings"));
|
||
|
||
builder.Services.AddRazorComponents()
|
||
.AddInteractiveServerComponents();
|
||
|
||
var app = builder.Build();
|
||
// (Rurociąg Middleware...)
|
||
app.Run();
|
||
```
|
||
|
||
**4. Wykorzystanie w serwisie lub komponencie Blazor:**
|
||
Logika biznesowa otrzymuje gotowy obiekt przy użyciu `IOptions<T>`.
|
||
|
||
```csharp
|
||
// SystemService.cs - rejestrowany w DI
|
||
using Microsoft.Extensions.Options;
|
||
|
||
public class SystemService
|
||
{
|
||
private readonly SystemSettingsOptions _settings;
|
||
|
||
// Klasyczne, poprawne wstrzykiwanie w architekturze .NET 10
|
||
public SystemService(IOptions<SystemSettingsOptions> options)
|
||
{
|
||
_settings = options.Value;
|
||
}
|
||
|
||
public void PerformOperation()
|
||
{
|
||
if (_settings.FeatureToggle)
|
||
{
|
||
// Nowa funkcjonalność uruchomiona z konfiguracji Hosta
|
||
for (int i = 0; i < _settings.MaxRetryAttempts; i++) { /*...*/ }
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## Wnioski architektoniczne
|
||
|
||
Porzucenie pliku `App.config` i interfejsów systemu Windows na rzecz **Generic Hosta** przetwarzającego `appsettings.json` to milowy krok w kierunku budowania skalowalnych i bezpiecznych aplikacji rozproszonych. W środowisku **.NET 10** konfiguracja jest mechanizmem odseparowanym, który naturalnie współpracuje z kontenerem *Dependency Injection* oraz systemami wdrażania (CI/CD). Programiści, zamiast siłować się z wczytywaniem i parsowaniem typów prostych (często rzucającymi wyjątkami podczas startu), mogą swobodnie pracować w warstwach biznesowych z użyciem walidowanych i bezstanowych klas wzorca Options, nad którymi pieczę operacyjną sprawuje potok uruchomieniowy. |