Files
Desktop2.0/e-book/Architektura ASP.NET Core i Ekosystem Blazor.md

115 lines
9.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## Wstęp merytoryczny: Ewolucja od .NET 4.8 do ASP.NET Core i Blazor w .NET 10
Przejście ze środowiska desktopowego, opartego o **.NET Framework 4.8** (WinForms, WPF), do nowoczesnego ekosystemu **ASP.NET Core** i frameworka **Blazor** reprezentuje fundamentalną zmianę paradygmatu architektonicznego. Ekosystem .NET ewoluował z platformy zamkniętej w systemie Windows (zależnej od ciężkiego API systemu operacyjnego) do wydajnego, wieloplatformowego rozwiązania open-source. ASP.NET Core wprowadza koncepcję zwinnego, modularnego potoku żądań HTTP obsługiwanego przez serwer **Kestrel**, podczas gdy Blazor pozwala na tworzenie interfejsów użytkownika bezpośrednio w języku C#, eliminując historyczną konieczność dzielenia logiki pomiędzy C# a JavaScript.
Transformacja z tradycyjnego oprogramowania typu "gruby klient" (Stateful) na środowisko webowe w .NET 10 wymaga zrozumienia mechanizmów asynchroniczności, nowoczesnego wstrzykiwania zależności (DI) oraz odmiennego cyklu życia aplikacji.
## Analiza Porównawcza: Desktop vs Nowoczesny Web (.NET 10)
Wiedza zdobyta przy tworzeniu aplikacji WPF i WinForms stanowi solidny fundament, jednak wymaga mapowania na wzorce używane w aplikacjach ASP.NET Core i komponentach Blazor:
| **Koncepcja Desktop (WPF/WinForms)** | **Odpowiednik w .NET 10 (ASP.NET Core / Blazor)** | **Charakter zmiany architektonicznej** |
| ----------------------------------------- | ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Window / UserControl** | **Komponent Razor (.razor)** | Przejście z XAML/projektanta WinForms na deklaratywny, oparty na C# i HTML komponent UI działający w przeglądarce lub na serwerze. |
| **App.config / Web.config** | **appsettings.json** | Rezygnacja ze statycznego, ciężkiego pliku XML na rzecz hierarchicznego pliku JSON, z wbudowanym wsparciem wstrzykiwania zależności i konfiguracji środowiskowej. |
| **Zdarzenia UI (Click, Loaded)** | **EventCallback / OnInitializedAsync** | Zdarzenia systemowe i cykl życia stają się w pełni asynchroniczne i zintegrowane z cyklem renderowania frameworka Blazor. |
| **Globalne instancje (Static/Singleton)** | **Dependency Injection (Wbudowany kontener DI)** | Stan w ASP.NET Core jest zarządzany poprzez usługi o ściśle określonym cyklu życia (Transient, Scoped, Singleton) rejestrowane w klasie bazowej. |
| **Stan w pamięci RAM aplikacji** | **Obwód (Circuit) / Stateless API** | Przejście z grubego klienta przechowującego dane lokalnie, na stan rozproszony lub utrzymywany na serwerze za pomocą połączenia SignalR w modelu Blazor Server. |
## Mechanika potoku ASP.NET Core i Modele Blazor
### Hosting i Middleware
Tradycyjna architektura .NET 4.8 często opierała się na potężnej i zmonolityzowanej bibliotece `System.Windows`. W nowoczesnym ASP.NET Core sercem aplikacji jest **Generic Host** oraz modularny rurociąg żądań HTTP (Request Pipeline) ułożony z komponentów **Middleware**. Żądanie przechodzi przez kolejne filtry, w których każde oprogramowanie pośredniczące może zmodyfikować kontekst, zanim zostanie przekazane do odpowiedniego sterownika lub komponentu renderującego.
### Modele uruchomieniowe Blazor
Blazor nie jest pojedynczą technologią, ale modelem komponentowym, który można osadzić w różnych konfiguracjach hostingowych:
* **Blazor Server:** Komponenty wykonywane są po stronie serwera wewnątrz aplikacji ASP.NET Core. Komunikacja UI odbywa się poprzez protokół WebSockets z użyciem SignalR. Stan powiązany z połączonym klientem nazywany jest "obwodem" (circuit). Pozwala to na pełny dostęp do zasobów serwera bez wysyłania kodu C# do przeglądarki.
* **Blazor WebAssembly (Wasm):** Aplikacja (wraz z runtime'em .NET) pobierana jest do przeglądarki klienta i wykonywana w piaskownicy przeglądarki (sandbox). Model ten umożliwia pełną pracę w trybie offline, w architekturze PWA (Progressive Web App) i zdejmuje obciążenie obliczeniowe z serwera.
* **Blazor Hybrid:** Łączy nowoczesne technologie webowe z oprogramowaniem natywnym.
## Dobre Praktyki i Antywzorce
W procesie przenoszenia logiki z .NET Framework 4.8 do architektury .NET 10 łatwo popełnić błędy polegające na przenoszeniu dawnych nawyków w nowe ramy technologiczne.
* **Antywzorzec (ZASADA ZERO HYBRYDY W 4.8):** Choć w oficjalnej dokumentacji pojawiają się informacje o integracji kontrolek `BlazorWebView` w celu modernizacji istniejących aplikacji WPF czy Windows Forms, należy to kategorycznie sprostować w odniesieniu do środowisk współdzielonych z .NET 4.8. Użycie natywnego Blazora w "starej" aplikacji Windows Forms w architekturze Framework 4.8 jest niemożliwe; mechanika hybrydowa z `BlazorWebView` wymaga zastosowania nowoczesnego środowiska uruchomieniowego w projektach natywnych .NET 6+. Migracja musi polegać na wydzieleniu logiki biznesowej do .NET Standard 2.0 i sukcesywnym podpinaniu nowoczesnego front-endu w architekturze .NET 10.
* **Antywzorzec:** Blokowanie wątków systemowych (np. `Thread.Sleep` czy synchroniczne `Wait()` na zadaniach). Aplikacje ASP.NET Core i serwer Kestrel zostały zoptymalizowane pod kątem tysięcy współbieżnych połączeń dzięki zastosowaniu mechanizmów asynchronicznych. Złamanie tej zasady w architekturze webowej zdestabilizuje serwer. Programowanie musi być w całości oparte o wzorce `async/await`.
* **Dobra praktyka:** Pełna separacja logiki prezentacji (Blazor/API) od logiki biznesowej i dostępu do danych (Entity Framework Core) za sprawą Dependency Injection. W ASP.NET Core wstrzykiwanie zależności nie jest zewnętrznym dodatkiem to wbudowany filar frameworka udostępniany poprzez interfejs `WebApplicationBuilder.Services`. Umożliwia to zjawisko całkowicie luźnego powiązania (loose coupling) i oddzielenie kodu renderującego UI od operacji I/O.
## Laboratorium kodu: Rejestracja usług i budowa komponentu
Poniżej przedstawiono implementację ilustrującą współdziałanie nowej mechaniki konfiguracyjnej oraz architektury asynchronicznej. Rejestracja zależności odbywa się w pliku punktu startowego `Program.cs`, co zastępuje w całości dawne konstrukcje z wykorzystaniem `Global.asax` i ciężkich konstruktorów.
```csharp
// Program.cs w .NET 10 (Uproszczony model Generic Host)
using Microsoft.EntityFrameworkCore;
using ModernApp.Data;
var builder = WebApplication.CreateBuilder(args);
// Rejestracja puli logiki poprzez wbudowany kontener DI
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();
// Użycie appsettings.json do odczytu Connection Stringa wstrzykiwanego do EF Core
builder.Services.AddDbContextFactory<AppDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
var app = builder.Build();
// Konfiguracja potoku żądań Middleware
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAntiforgery();
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode();
app.Run();
```
Mechanika po stronie klienta również ulega uproszczeniu, przechodząc z obiektów `Dispatcher` na zautomatyzowany cykl odświeżania cyklu życia. Poniżej przedstawiony jest w pełni asynchroniczny komponent odczytujący dane z systemu, respektujący zasady modelu bezstanowego po stronie UI:
```csharp
// TasksList.razor
@page "/tasks"
@inject ITaskService TaskService
<div class="task-board">
@if (_tasks == null)
{
<p><em>Ładowanie strumieniowe, proszę czekać...</em></p>
}
else
{
<table class="table">
@foreach (var task in _tasks)
{
<tr>
<td>@task.Title</td>
<td>@task.AssignedTo</td>
</tr>
}
</table>
}
</div>
@code {
private List<TaskDto>? _tasks;
// Asynchroniczny odpowiednik zdarzenia Form_Load / UserControl.Loaded
protected override async Task OnInitializedAsync()
{
// Wywołanie usługi wstrzykniętej z DI - brak blokowania wątku interfejsu (UI Thread)
_tasks = await TaskService.GetActiveTasksAsync();
}
}
```
## Wnioski architektoniczne
Porzucenie zmonolityzowanego modelu *Stateful* (aplikacji stanowych Desktop w .NET 4.8) na rzecz ekosystemu **.NET 10**, gdzie dominuje bezstanowa architektura potoku żądań (Middleware) i elastyczne hostowanie interfejsu (Blazor Server/WebAssembly), wymaga transformacji sposobu projektowania pamięci i stanu aplikacji. Blazor upodabnia pisanie nowoczesnego, responsywnego interfejsu klienta do modelu podobnego pod względem mentalnym do wzorca znanej abstrakcji klas c#, jednak eliminuje bezpośredni, procesowy dostęp do hardwareu stacji roboczej z poziomu interfejsu, wymuszając w pełni asynchroniczną i bezpieczną integrację poprzez komunikację sieciową (API i potoki wstrzykiwania zależności).