vault backup: 2026-05-14 19:46:36

This commit is contained in:
2026-05-14 19:46:36 +02:00
commit 83707a9abc
34 changed files with 43105 additions and 0 deletions
@@ -0,0 +1,106 @@
## Wstęp merytoryczny: Wbudowane wstrzykiwanie zależności pod kontrolą Hosta
Przejście z architektury **.NET Framework 4.8** na nowoczesny ekosystem **.NET 10** wymusza zmianę sposobu zarządzania cyklem życia obiektów i ich zależnościami. W klasycznych aplikacjach desktopowych (WPF, WinForms) wstrzykiwanie zależności (Dependency Injection, DI) było mechanizmem opcjonalnym, często dodawanym za pomocą zewnętrznych bibliotek (np. Autofac, Ninject). W architekturze ASP.NET Core wbudowane wstrzykiwanie zależności stanowi nierozerwalny fundament platformy.
Centralnym punktem zarządzającym wstrzykiwaniem zależności jest **Generic Host** (Host Ogólny), najczęściej powoływany za pomocą instancji `WebApplicationBuilder`. Host hermetyzuje wszystkie zasoby aplikacji: serwer HTTP, konfigurację, potok oprogramowania pośredniczącego (Middleware) oraz centralny kontener DI. Oznacza to, że w środowisku webowym to nie system operacyjny Windows ani kod interfejsu użytkownika zarządza pamięcią obiektów, lecz wysoce zoptymalizowana infrastruktura Hosta.
## Analiza Porównawcza: Zarządzanie zależnościami (Desktop vs Web)
| **Koncepcja Desktop (.NET 4.8)** | **Odpowiednik w .NET 10 (Generic Host)** | **Charakter zmiany architektonicznej** |
| --- | --- | --- |
| **Ręczne powoływanie obiektów (`new`)** | **Kontener DI (`builder.Services`)** | Odrzucenie ścisłego powiązania (tight coupling). Aplikacja polega na odwróceniu kontroli (IoC), a Host wstrzykuje instancje do konstruktorów. |
| **Zmienne statyczne / Wzorzec Singleton** | **Rejestracja o cyklu życia (Singleton/Scoped)** | Eliminacja globalnego stanu aplikacji (Stateful) na rzecz zarządzania bytem obiektów w obrębie cyklu życia bezstanowego żądania HTTP (Stateless). |
| **Zewnętrzne biblioteki DI** | **Wbudowane `Microsoft.Extensions.DependencyInjection`** | Standaryzacja. Mechanizm DI jest zintegrowany bezpośrednio wewnątrz Hosta i dostarczany natywnie przez framework. |
| **Ścisłe zależności między warstwami** | **Wstrzykiwanie przez konstruktor lub `@inject`** | Logika biznesowa jest przekazywana do nowoczesnych kontrolerów lub komponentów Blazor wyłącznie przez mechanizmy wbudowane w platformę. |
### Głębokie Nurkowanie (Deep Dive): Anatomia DI w Generic Host
W modelu ASP.NET Core proces inicjalizacji i orkiestracji działania aplikacji opiera się na dwóch fazach budowy Hosta. W fazie początkowej obiekt `WebApplicationBuilder` udostępnia właściwość `Services` reprezentującą kolekcję usług (`IServiceCollection`). To na tym etapie infrastruktura dodaje logikę dostępu do bazy danych, logowania, autoryzacji oraz renderowania komponentów interfejsu.
Kiedy programista wywołuje metodę `builder.Build()`, Host zatrzaskuje konfigurację, generuje docelowy kontener DI (`IServiceProvider`) i konfiguruje środowisko uruchomieniowe wraz z wieloplatformowym serwerem HTTP Kestrel. Od tego momentu każda składowa potoku Middleware, każdy kontroler oraz każdy komponent Blazor otrzymuje swoje zależności wyłącznie w sposób automatyczny na etapie wykonania. Model ten eliminuje narzut związany z manualnym przekazywaniem parametrów systemowych w głąb drzewa wywołań.
## Dobre Praktyki i Antywzorce
* **Antywzorzec: Ręczna rezolucja usług:** Pobieranie instancji poprzez anty-wzorzec *Service Locator* (np. bezpośrednie odpytywanie `ServiceProvider` w warstwie logiki) łamie spójność kontroli sprawowanej przez Hosta i ogranicza przejrzystość.
* **Dobra Praktyka: Wstrzykiwanie przez konstruktor (Constructor Injection):** Zależności powinny być zawsze deklarowane jawnie jako parametry konstruktora (lub poprzez dyrektywę `@inject` w plikach `.razor`). Gwarantuje to testowalność i przejrzystość wymogów danej klasy, co ułatwia zarządzanie dostarczanymi zależnościami.
## Laboratorium kodu: Rejestracja usług i ich użycie w architekturze Hosta
Poniższy przykład demonstruje ewolucję inicjalizacji na poziomie punktu wejścia aplikacji. Użyto w nim wzorca Minimal API, gdzie `Generic Host` ładuje mechanizmy infrastruktury z jednego punktu, pozwalając na precyzyjne odizolowanie bazy danych od interfejsu UI.
```csharp
// Program.cs w .NET 10 (Konfiguracja Hosta)
using Microsoft.EntityFrameworkCore;
using ModernApp.Data;
// 1. Inicjalizacja Hosta i infrastruktury
var builder = WebApplication.CreateBuilder(args);
// 2. Rejestracja wbudowanego mechanizmu wstrzykiwania zależności (DI)
// Usługi środowiskowe (np. konfiguracja JSON) są dostępne od razu z poziomu Hosta
builder.Services.AddDbContextFactory<AppDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")
?? throw new InvalidOperationException("Brak konfiguracji bazy danych."))); //
// Rejestracja frameworka komponentów i obsługi cyklu życia UI
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents(); //
// 3. Zbudowanie Hosta zatrzaśnięcie kontenera DI
var app = builder.Build(); //
// (Konfiguracja bezstanowego potoku Middleware...)
app.UseHttpsRedirection(); //
app.UseAntiforgery(); //
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode(); //
// 4. Start Hosta i serwera Kestrel
app.Run(); //
```
Zastosowanie wstrzykniętych zasobów w asynchronicznym środowisku webowym za pomocą dedykowanej dyrektywy frameworka:
```html
@* TasksList.razor *@
@page "/tasks"
@using ModernApp.Data
@using Microsoft.EntityFrameworkCore
@* Deklaratywne żądanie wstrzyknięcia usługi utrzymywanej przez Generic Host *@
@inject IDbContextFactory<AppDbContext> DbFactory
<div class="task-board">
@if (_tasks == null)
{
<p><em>Pobieranie danych ze strumienia DI...</em></p>
}
else
{
<table class="table">
@foreach (var task in _tasks)
{
<tr>
<td>@task.Title</td>
</tr>
}
</table>
}
</div>
@code {
private List<TaskDto>? _tasks;
// Metoda cyklu życia, w której asynchronicznie zużywamy zasoby dostarczone z Hosta
protected override async Task OnInitializedAsync()
{
await using var context = DbFactory.CreateDbContext();
_tasks = await context.Tasks.ToListAsync();
}
}
```
## Wnioski architektoniczne
Przesunięcie zarządzania bytem i instancjonowaniem obiektów z poziomu kodu sterowanego zdarzeniami w architekturze Desktop (np. powiązanej z cyklem życia kontrolki w WPF), bezpośrednio do wbudowanego, centralnego mechanizmu kontenera DI zintegrowanego z modelem **Generic Host**, pozwala na radykalne podniesienie testowalności i skalowalności. Architektura w .NET 10 zapobiega wyciekom pamięci dzięki standaryzowanym cyklom życia obiektów (Transient, Scoped, Singleton) zarządzanym i powiązanym z ramami czasowymi żądań HTTP przetwarzanych przez Middleware. Umożliwia to zwinne budowanie i wdrażanie odseparowanej, ustandaryzowanej logiki aplikacji.