.NET 9 Blazor: Pełnostackowy rozwój aplikacji z Blazor United w 2026
.NET 9 Blazor United łączy statyczny SSR, Server i WebAssembly w jednym frameworku full-stack. Praktyczny poradnik obejmujący tryby renderowania, streaming rendering, wstrzykiwanie zależności i wzorce produkcyjne.

.NET 9 wprowadza Blazor United — architekturę, która scala trzy dotychczas rozdzielne strategie renderowania w jeden spójny model programowania. Deweloperzy zyskują możliwość łączenia statycznego Server-Side Rendering, interaktywności przez SignalR oraz WebAssembly w obrębie tego samego komponentu, a nawet tej samej strony. Eliminuje to kompromisy między wydajnością pierwszego załadowania, SEO a możliwościami aplikacji działających całkowicie po stronie klienta. Blazor United to odpowiedź na rosnące wymagania współczesnych aplikacji webowych, które muszą być jednocześnie szybkie, interaktywne i łatwe w utrzymaniu.
Blazor United to zunifikowany model renderowania w .NET 9, który pozwala mieszać tryby statyczne, Server (SignalR) i WebAssembly w jednej aplikacji bez konieczności tworzenia oddzielnych projektów. Komponent może renderować się statycznie dla SEO, a po załadowaniu przełączyć się na interaktywność przez WebAssembly — wszystko automatycznie.
Konfiguracja projektu .NET 9 Blazor Web App
Rozpoczęcie pracy z Blazor United wymaga .NET 9 SDK. Nowy szablon blazorweb umożliwia wybór trybu interaktywności już podczas tworzenia projektu. Opcja --interactivity Auto włącza hybrydowe renderowanie — serwer obsługuje pierwszą interakcję, a następnie aplikacja przełącza się na WebAssembly po pobraniu runtime'u w tle.
# Create a new Blazor Web App with all render modes enabled
dotnet new blazorweb -n FullStackApp --interactivity Auto --all-interactive false
cd FullStackApp
dotnet runParametr --all-interactive false wymusza selektywną interaktywność — domyślnie komponenty renderują się statycznie, chyba że explicite zaznaczono inaczej przez atrybut @rendermode. To podejście optymalizuje transfer danych i eliminuje niepotrzebne połączenia SignalR dla treści, która nie wymaga dynamiki.
Tryby renderowania i ich zastosowania
Blazor United opiera się na czterech trybach renderowania, które można przypisywać zarówno całym stronom, jak i pojedynczym komponentom. Każdy tryb ma specyficzne zastosowania zależne od wymagań dotyczących wydajności, SEO i interaktywności.
| Render Mode | Hosting | Interactivity | Best For | |---|---|---|---| | Static SSR | Server | None | Marketing pages, docs, SEO content | | Interactive Server | Server via SignalR | Full | Dashboards, CRUD, forms | | Interactive WebAssembly | Browser via WASM | Full | Offline, heavy client-side logic | | Interactive Auto | Server then WASM | Full | Best of both — fast load + independence |
Statyczny SSR generuje czysty HTML bez JavaScript — idealny dla landing pages, dokumentacji i wszystkiego, co musi być indeksowane przez wyszukiwarki. Interactive Server utrzymuje połączenie WebSocket i wykonuje kod C# na serwerze, co eliminuje opóźnienia sieciowe dla aplikacji wymagających częstych aktualizacji UI. WebAssembly przenosi całą logikę do przeglądarki, umożliwiając offline-first experiences i złożone operacje bez obciążania serwera. Auto mode łączy oba — pierwsze kliknięcie obsługuje serwer, a w międzyczasie pobiera runtime WASM dla przyszłych interakcji.
@page "/dashboard"
@rendermode InteractiveServer
<PageTitle>Dashboard</PageTitle>
<h1>Real-Time Metrics</h1>
<!-- This component renders interactively via SignalR -->
<MetricsChart />
<!-- Static content below renders as plain HTML -->
<footer>Updated every 5 seconds</footer>W powyższym przykładzie cała strona /dashboard renderuje się przez SignalR. Oznacza to, że każde zdarzenie (kliknięcie, input) wysyła wiadomość do serwera, który przetwarza logikę i zwraca zaktualizowany fragment DOM. Ten tryb sprawdza się w dashboardach czasu rzeczywistego, gdzie dane zmieniają się co kilka sekund i wymagają synchronizacji z bazą danych.
Adaptacyjne komponenty mogą wykrywać kontekst renderowania i dostosowywać zachowanie:
@if (RendererInfo.IsInteractive)
{
<button @onclick="HandleClick">Interactive Action</button>
}
else
{
<a href="/fallback">Static Fallback Link</a>
}
@code {
private void HandleClick()
{
// Runs only in interactive modes (Server or WASM)
}
}RendererInfo.IsInteractive zwraca true tylko w trybach Server, WebAssembly i Auto. Dzięki temu ten sam komponent może być używany zarówno w statycznych dokumentach, jak i interaktywnych modułach aplikacji — w pierwszym przypadku wyświetli link, w drugim przycisk z logiką C#.
Streaming rendering dla wydajności postrzeganej
Atrybut [StreamRendering] włącza progresywne renderowanie HTML. Zamiast czekać na zakończenie wszystkich asynchronicznych operacji, Blazor wysyła fragmenty strony w miarę ich gotowości. Użytkownik widzi szkielet UI niemal natychmiast, a treść pojawia się stopniowo w tle.
@page "/products"
@attribute [StreamRendering]
<PageTitle>Product Catalog</PageTitle>
@if (products is null)
{
<p>Loading products...</p>
}
else
{
<div class="product-grid">
@foreach (var product in products)
{
<ProductCard Item="@product" />
}
</div>
}
@code {
private List<Product>? products;
// Data loads asynchronously; streaming pushes updates to the browser
protected override async Task OnInitializedAsync()
{
products = await ProductService.GetAllAsync();
}
}Podczas pierwszego renderu przeglądarka otrzymuje HTML z komunikatem "Loading products...". Gdy ProductService.GetAllAsync() zakończy pobieranie danych, Blazor wysyła aktualizację przez ten sam strumień HTTP, zastępując placeholder listą produktów. Z perspektywy użytkownika strona ładuje się dwuetapowo — najpierw nagłówek i layout, potem zawartość. Redukuje to postrzegane opóźnienie, szczególnie przy wolnych zapytaniach do bazy danych.
Streaming rendering działa tylko w trybie statycznego SSR. Jeśli komponent ma @rendermode InteractiveServer, atrybut [StreamRendering] zostanie zignorowany — SignalR zarządza aktualizacjami przez własny protokół.
Wstrzykiwanie zależności przez konstruktory
.NET 9 wprowadza primary constructors dla komponentów Razor. Zamiast deklarować właściwości z [Inject], można przekazać zależności bezpośrednio w konstruktorze, co poprawia czytelność i eliminuje boilerplate.
@page "/orders"
@rendermode InteractiveServer
<h2>Order History</h2>
@if (orders is not null)
{
<table>
<thead>
<tr><th>Order ID</th><th>Date</th><th>Total</th></tr>
</thead>
<tbody>
@foreach (var order in orders)
{
<tr>
<td>@order.Id</td>
<td>@order.PlacedAt.ToShortDateString()</td>
<td>@order.Total.ToString("C")</td>
</tr>
}
</tbody>
</table>
}
@code {
// Constructor injection via primary constructor
[Inject] public required IOrderService OrderService { get; set; }
[Inject] public required NavigationManager Nav { get; set; }
private List<Order>? orders;
protected override async Task OnInitializedAsync()
{
orders = await OrderService.GetRecentOrdersAsync();
}
}W tym przykładzie IOrderService i NavigationManager są wstrzykiwane przez kontenera DI w momencie tworzenia instancji komponentu. Modifier required wymusza inicjalizację przed pierwszym użyciem, co chroni przed błędami NullReferenceException w runtime. Taka składnia jest spójna z resztą ekosystemu C# 12 i ułatwia testowanie — wystarczy stworzyć mock serwisu i przekazać go do komponentu w unit teście.
Gotowy na rozmowy o .NET?
Ćwicz z naszymi interaktywnymi symulatorami, flashcards i testami technicznymi.
Interactive Auto — najlepsze z dwóch światów
Tryb Auto łączy Server i WebAssembly w jednym komponencie. Pierwsza interakcja (kliknięcie, input) jest obsługiwana przez SignalR, jednocześnie w tle pobiera się runtime .NET WASM. Po zakończeniu pobierania kolejne interakcje wykonują się lokalnie w przeglądarce bez opóźnień sieciowych.
@page "/chat"
@rendermode InteractiveAuto
<h2>Live Chat</h2>
<div class="chat-messages">
@foreach (var msg in messages)
{
<div class="message">@msg.Author: @msg.Text</div>
}
</div>
<input @bind="newMessage" @onkeydown="HandleKey" placeholder="Type a message..." />
@code {
[Inject] public required IChatService ChatService { get; set; }
private List<ChatMessage> messages = new();
private string newMessage = string.Empty;
protected override async Task OnInitializedAsync()
{
messages = await ChatService.GetRecentMessagesAsync();
}
private async Task HandleKey(KeyboardEventArgs e)
{
if (e.Key == "Enter" && !string.IsNullOrWhiteSpace(newMessage))
{
await ChatService.SendAsync(newMessage);
newMessage = string.Empty;
}
}
}Podczas pierwszego wejścia na /chat przeglądarka otrzymuje HTML z listą wiadomości. Jeśli użytkownik od razu zacznie pisać, zdarzenie @onkeydown trafia do serwera przez SignalR — odpowiedź przychodzi w ciągu 20–50 ms zależnie od latencji. Równolegle w tle ładuje się 1.5–2 MB runtime .NET (skompresowany gzip). Po zakończeniu pobierania Blazor automatycznie przełącza renderowanie na WebAssembly — kolejne naciśnięcia klawiszy wykonują się lokalnie bez żadnego ruchu sieciowego. Użytkownik nie zauważa momentu przełączenia, a UX pozostaje płynny.
Interactive Auto eliminuje kompromis między szybkością pierwszego załadowania a responsywnością aplikacji. Sprawdza się w formularzach z walidacją po stronie klienta, edytorach WYSIWYG i wszystkich interfejsach wymagających natychmiastowej reakcji na input użytkownika. Jest to domyślna rekomendacja dla większości nowych projektów Blazor w 2026 roku, co często pojawia się w blazor interview questions 2026 jako best practice.
Resilient connections — obsługa utraconych połączeń
Tryb Interactive Server opiera się na WebSocket. Utrata połączenia (zmiana sieci, uśpienie laptopa, restart serwera) przerywa działanie aplikacji. .NET 9 wprowadza konfigurowalny mechanizm ponownego łączenia z wykładniczym backoff.
Blazor.start({
circuit: {
reconnectionOptions: {
retryIntervalMilliseconds: (retryNumber) => {
// Exponential backoff: 200ms, 400ms, 800ms, max 30s
return Math.min(200 * Math.pow(2, retryNumber), 30000);
},
maxRetries: 15
}
}
});Domyślna konfiguracja próbuje połączyć się 8 razy z interwałami 0, 2s, 10s, 30s. W środowiskach z niestabilnym internetem (mobile, hotspot) warto zwiększyć maxRetries do 15 i skrócić początkowe opóźnienie do 200 ms. Wykładniczy backoff zapobiega przeciążeniu serwera w przypadku masowej utraty połączeń (np. restart klastra Kubernetes).
Blazor wyświetla domyślny UI podczas próby ponownego połączenia — niebieski pasek na dole ekranu z tekstem "Attempting to reconnect...". Można go zastąpić własnym komponentem przez nadpisanie elementu #components-reconnect-modal w CSS lub całkowitą podmianę logiki w JavaScript.
W trybie Auto po utracie połączenia SignalR aplikacja automatycznie przełącza się na WebAssembly (jeśli runtime został już pobrany). Oznacza to, że użytkownik może kontynuować pracę offline — formularz będzie działał lokalnie, a wysyłka danych nastąpi po przywróceniu łączności. To kluczowa przewaga nad czystym Interactive Server w aplikacjach mission-critical.
Selektywna interaktywność dla optimum wydajności
Parametr --all-interactive false wymusza świadome decyzje o interaktywności. Domyślnie każdy komponent renderuje się statycznie — deweloper musi jawnie dodać @rendermode, aby włączyć SignalR lub WASM. To podejście drastycznie redukuje payload JavaScript i liczbę otwartych WebSocket.
@page "/privacy"
@attribute [ExcludeFromInteractiveRouting]
<PageTitle>Privacy Policy</PageTitle>
<!-- This page always renders as static HTML -->
<!-- Even if global interactivity is enabled -->
<article>
<h1>Privacy Policy</h1>
<p>Last updated: April 2026</p>
<!-- Content -->
</article>Atrybut [ExcludeFromInteractiveRouting] gwarantuje, że strona /privacy zawsze renderuje się jako czysty HTML, nawet jeśli globalna konfiguracja wymusza Interactive Server. Jest to szczególnie istotne dla stron wymaganych przez regulacje (privacy policy, terms of service, cookie consent) — muszą być dostępne bez JavaScript i ładować się w mniej niż sekundę.
W praktyce większość aplikacji Blazor United składa się z mieszanki stron statycznych (landing, docs, legal), komponentów Interactive Server (dashboardy, formularze CRUD), komponentów Interactive Auto (edytory, chat, real-time collaboration) oraz komponentów WASM (offline forms, heavy client-side calculations). Taka kombinacja minimalizuje koszty infrastruktury, poprawia SEO i zapewnia doskonały UX. Zgodnie z najnowszym asp.net blazor tutorial Microsoft, takie rozłożenie proporcji jest optymalne dla większości aplikacji enterprise.
Ahead-of-Time compilation dla maksymalnej wydajności
WebAssembly w Blazor domyślnie używa interpretowanego .NET runtime. AOT (Ahead-of-Time) kompiluje assemblies do natywnego WebAssembly podczas budowania, eliminując JIT overhead. Aplikacje zyskują znacząco lepszą wydajność w zamian za dłuższy czas budowania i większy rozmiar bundle.
# Publish with AOT for production
dotnet publish -c Release -p:RunAOTCompilation=trueAOT jest szczególnie opłacalne dla aplikacji z intensywnymi obliczeniami po stronie klienta — edytory graficzne, silniki gier 2D, parsery dużych JSON, kalkulatory finansowe. Dla typowych CRUD-ów różnica będzie niezauważalna, a zwiększony rozmiar bundle może pogorszyć Time to Interactive na wolnych połączeniach.
W .NET 9 AOT wspiera pełne odbicie i większość bibliotek BCL (Base Class Library). Wcześniejsze wersje miały ograniczenia w dynamicznym tworzeniu typów i serializacji JSON — obecnie działa to transparentnie z System.Text.Json i większością ORM.
Zacznij ćwiczyć!
Sprawdź swoją wiedzę z naszymi symulatorami rozmów i testami technicznymi.
Kluczowe wnioski
Blazor United w .NET 9 stanowi przełom w architekturze full-stack aplikacji webowych. Eliminuje konieczność wyboru między wydajnością a interaktywnością, umożliwiając płynne łączenie trybów renderowania w obrębie jednej aplikacji.
- Zunifikowany model programowania — jeden język (C#), jeden runtime, trzy tryby renderowania bez kompromisów
- Optymalna wydajność — statyczny SSR dla SEO, SignalR dla dashboardów, WASM dla offline i heavy computations
- Interactive Auto mode — automatyczne przełączanie z serwera na klient po pobraniu runtime WASM w tle
- Selektywna interaktywność — każdy komponent może mieć własny tryb renderowania, co minimalizuje payload i koszty infrastruktury
- Streaming rendering — progresywne ładowanie HTML redukuje postrzegane opóźnienie
- Resilient connections — konfigurowalne reconnection z wykładniczym backoff i automatyczne fallback do WASM
- AOT compilation — znacząco lepsza wydajność WASM dzięki kompilacji do natywnego kodu
Blazor United to obecnie najbardziej zaawansowany framework full-stack dla deweloperów .NET. Aplikacje budowane w tym modelu osiągają wydajność porównywalną z najlepszymi frameworkami JavaScript, zachowując zalety silnego typowania C# i integracji z ekosystemem .NET. W 2026 roku znajomość blazor united full stack jest standardowym wymaganiem dla senior .NET developers.
Zacznij ćwiczyć!
Sprawdź swoją wiedzę z naszymi symulatorami rozmów i testami technicznymi.
Tagi
Udostępnij
Powiązane artykuły

Entity Framework Core: Optymalizacja wydajności i najlepsze praktyki w 2026
Kompleksowy przewodnik po optymalizacji EF Core 10. Poznaj techniki zwiększania wydajności zapytań, zarządzania pamięcią i skalowania aplikacji .NET.

Clean Architecture w .NET: Praktyczny Przewodnik
Opanowanie Clean Architecture w .NET z C#. Poznanie zasad SOLID, separacji warstw i wzorców implementacyjnych dla aplikacji łatwych w utrzymaniu.

Pytania rekrutacyjne C# i .NET: Kompletny przewodnik 2026
17 najczesciej zadawanych pytan rekrutacyjnych z C# i .NET. LINQ, async/await, Dependency Injection, Entity Framework Core i ASP.NET Core ze szczegolowymi odpowiedziami.