# .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. - Published: 2026-04-26 - Updated: 2026-04-26 - Author: SharpSkill - Tags: dotnet, blazor, aspnet-core, webassembly, full-stack - Reading time: 8 min --- .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. > **Czym jest Blazor United?** > > 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. ```bash # Create a new Blazor Web App with all render modes enabled dotnet new blazorweb -n FullStackApp --interactivity Auto --all-interactive false cd FullStackApp dotnet run ``` Parametr `--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. ```csharp // Components/Pages/Dashboard.razor @page "/dashboard" @rendermode InteractiveServer Dashboard

Real-Time Metrics

``` 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: ```csharp // Components/Shared/AdaptiveComponent.razor @if (RendererInfo.IsInteractive) { } else { Static Fallback Link } @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. ```csharp // Components/Pages/Products.razor @page "/products" @attribute [StreamRendering] Product Catalog @if (products is null) {

Loading products...

} else {
@foreach (var product in products) { }
} @code { private List? 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. ```csharp // Components/Pages/OrderHistory.razor @page "/orders" @rendermode InteractiveServer

Order History

@if (orders is not null) { @foreach (var order in orders) { }
Order IDDateTotal
@order.Id @order.PlacedAt.ToShortDateString() @order.Total.ToString("C")
} @code { // Constructor injection via primary constructor [Inject] public required IOrderService OrderService { get; set; } [Inject] public required NavigationManager Nav { get; set; } private List? 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. ## 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. ```csharp // Components/Pages/Chat.razor @page "/chat" @rendermode InteractiveAuto

Live Chat

@foreach (var msg in messages) {
@msg.Author: @msg.Text
}
@code { [Inject] public required IChatService ChatService { get; set; } private List 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. ```javascript // wwwroot/app.js — Custom reconnection configuration 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. ```csharp // Components/Pages/Privacy.razor @page "/privacy" @attribute [ExcludeFromInteractiveRouting] Privacy Policy

Privacy Policy

Last updated: April 2026

``` 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. ```bash # Publish with AOT for production dotnet publish -c Release -p:RunAOTCompilation=true ``` AOT 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. ## 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. --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/pl/blog/dotnet/dotnet-9-blazor-united-full-stack-development