## 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(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() .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 DbFactory
@if (_tasks == null) {

Pobieranie danych ze strumienia DI...

} else { @foreach (var task in _tasks) { }
@task.Title
}
@code { private List? _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.