.NET 9 Blazor: Desenvolvimento Full-Stack com Blazor United em 2026

.NET 9 Blazor United combina renderização estática SSR, Server e WebAssembly em um framework full-stack unificado. Tutorial prático cobrindo modos de renderização, streaming, injeção por construtor e padrões prontos para produção.

Desenvolvimento full-stack com .NET 9 Blazor United e múltiplos modos de renderização

Blazor United no .NET 9 une três estratégias de renderização — renderização estática do lado do servidor (SSR), Server interativo e WebAssembly — em um único framework full-stack coeso. Esse modelo unificado, introduzido no .NET 8 e aprimorado no .NET 9, elimina a necessidade de escolher entre diferentes modelos de hospedagem do Blazor antes mesmo de escrever a primeira linha de código.

Blazor United em resumo

Blazor United permite combinar SSR estático, interatividade Server e interatividade WebAssembly dentro da mesma aplicação. Cada componente declara independentemente seu modo de renderização, proporcionando controle granular sobre desempenho e interatividade por página.

Configurando uma aplicação Blazor Web com .NET 9

O template blazorweb do .NET 9 gera um projeto pré-configurado para os três modos de renderização. A configuração requer o SDK do .NET 9 (versão 9.0.100 ou posterior) e cria tanto o projeto do servidor quanto o do cliente (WASM) em um único comando.

bash
# Criar uma nova Blazor Web App com todos os modos de renderização habilitados
dotnet new blazorweb -n FullStackApp --interactivity Auto --all-interactive false
cd FullStackApp
dotnet run

A flag --interactivity Auto habilita os modos de renderização Server e WebAssembly. O parâmetro --all-interactive false mantém a renderização estática SSR como padrão, de modo que a interatividade é ativada componente por componente em vez de globalmente.

Entendendo os modos de renderização do Blazor no .NET 9

Cada componente em uma Blazor Web App adota um modo de renderização que determina onde ele é executado, se suporta interatividade e como se comunica com o servidor. O .NET 9 oferece quatro modos distintos.

| Modo de renderização | Hospedagem | Interatividade | Ideal para | |---|---|---|---| | SSR estático | Servidor | Nenhuma | Páginas de marketing, documentação, conteúdo SEO | | Interactive Server | Servidor via SignalR | Completa | Dashboards, CRUD, formulários | | Interactive WebAssembly | Navegador via WASM | Completa | Modo offline, lógica intensiva no cliente | | Interactive Auto | Servidor depois WASM | Completa | O melhor dos dois mundos — carregamento rápido + independência |

O modo de renderização é definido no nível do componente com a diretiva @rendermode. Essa granularidade por componente significa que uma única página pode mesclar seções estáticas e interativas.

Components/Pages/Dashboard.razorcsharp
@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>

Uma adição na API do .NET 9 — ComponentBase.RendererInfo — permite que os componentes detectem seu modo de renderização atual em tempo de execução, possibilitando lógica condicional baseada no contexto de execução.

Components/Shared/AdaptiveComponent.razorcsharp
@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)
    }
}

Renderização em streaming para páginas com carga assíncrona

Páginas SSR estáticas que buscam dados de forma assíncrona podem bloquear a resposta até que todas as tarefas sejam concluídas. A renderização em streaming resolve esse problema enviando HTML de placeholder imediatamente e, em seguida, transmitindo o conteúdo final conforme os dados chegam. No .NET 9, o atributo [StreamRendering] não requer mais o parâmetro true — ele é habilitado por padrão.

Components/Pages/Products.razorcsharp
@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();
    }
}

A renderização em streaming utiliza a codificação de transferência em partes (chunked transfer encoding) do HTTP/1.1, compatível com todos os navegadores modernos. O conteúdo de placeholder é exibido instantaneamente, e a marcação final o substitui sem recarregamento completo da página.

Injeção por construtor em componentes Blazor

O .NET 9 introduz a injeção por construtor para componentes Blazor, complementando a diretiva @inject e o atributo [Inject] existentes. Combinada com os construtores primários do C# 12, as dependências de serviços se tornam parte da assinatura de tipo do componente.

Components/Pages/OrderHistory.razorcsharp
@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();
    }
}

A injeção por construtor torna as dependências explícitas e simplifica os testes unitários. Os serviços registrados em Program.cs são resolvidos automaticamente, incluindo os serviços com chave adicionados via builder.Services.AddKeyedScoped<T>().

Pronto para mandar bem nas entrevistas de .NET?

Pratique com nossos simuladores interativos, flashcards e testes tecnicos.

Modo Interactive Auto — o melhor dos dois mundos

O modo Auto oferece o menor tempo de carregamento percebido. Na primeira visita, o componente é executado no servidor via SignalR enquanto o runtime do WebAssembly é baixado em segundo plano. Nas visitas seguintes, a execução passa inteiramente para o navegador.

Components/Pages/Chat.razorcsharp
@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;
        }
    }
}

O modo Auto exige que as dependências e a lógica do componente funcionem em ambos os contextos, servidor e WASM. Os serviços devem ser abstraídos por meio de interfaces e registrados nos contêineres de injeção de dependência tanto do servidor quanto do cliente.

Reconexão e resiliência no .NET 9

O .NET 9 reescreve a lógica de reconexão do Blazor Server com uma estratégia de backoff exponencial. Em vez de tentar novamente em intervalos fixos, o framework começa com tentativas rápidas e aumenta progressivamente o intervalo — reduzindo a carga do servidor durante interrupções e recuperando-se rapidamente de falhas breves.

Melhorias principais:

  • Navegar de volta a uma aba dispara uma tentativa de reconexão imediata
  • Se o servidor já liberou o circuito, a página é atualizada automaticamente
  • A interface padrão exibe "Reconectando ao servidor..." com um indicador de progresso
  • Os intervalos de nova tentativa são configuráveis via Blazor.start()
wwwroot/app.js — Custom reconnection configurationjavascript
Blazor.start({
    circuit: {
        reconnectionOptions: {
            retryIntervalMilliseconds: (retryNumber) => {
                // Exponential backoff: 200ms, 400ms, 800ms, max 30s
                return Math.min(200 * Math.pow(2, retryNumber), 30000);
            },
            maxRetries: 15
        }
    }
});

SSR estático com interatividade seletiva

A arquitetura recomendada para a maioria das Blazor Web Apps em 2026 começa com SSR estático como padrão, adicionando interatividade apenas onde for necessário. O atributo [ExcludeFromInteractiveRouting] (novo no .NET 9) marca as páginas que devem permanecer estáticas — útil para páginas que dependem de cookies HTTP ou do ciclo de requisição/resposta.

Components/Pages/Privacy.razorcsharp
@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>

Esse padrão funciona bem com MapStaticAssets, um novo middleware do .NET 9 que comprime e adiciona fingerprints aos arquivos estáticos no momento do build, substituindo a abordagem anterior de UseStaticFiles com uma entrega otimizada pronta para uso.

Ganhos de desempenho com a compilação AOT do .NET 9

A compilação AOT (Ahead-of-Time) do .NET 9 reduz o tamanho dos payloads do WebAssembly em até 40% em comparação com o .NET 8. A inicialização do Blazor WASM é 25% mais rápida segundo os benchmarks do Google Lighthouse. Esses ganhos são aplicados automaticamente ao publicar com AOT habilitado.

bash
# Publish with AOT for production
dotnet publish -c Release -p:RunAOTCompilation=true

A compressão de WebSocket também está habilitada por padrão para componentes interativos Server. Uma Content Security Policy (frame-ancestors: 'self') é aplicada automaticamente para mitigar vetores de ataque relacionados à compressão.

Comece a praticar!

Teste seus conhecimentos com nossos simuladores de entrevista e testes tecnicos.

Conclusão

  • Blazor United no .NET 9 elimina a decisão do modelo de hospedagem ao combinar SSR estático, Server e WebAssembly em um único projeto
  • Os modos de renderização são configurados por componente com @rendermode para otimizar cada página de forma independente — estático para SEO, Server para dashboards, Auto para cenários híbridos
  • A renderização em streaming com [StreamRendering] elimina atrasos de carregamento em páginas com alta carga assíncrona
  • A injeção por construtor (nova no .NET 9) torna as dependências dos componentes explícitas e testáveis
  • O modo Auto entrega um primeiro carregamento rápido via Server e depois muda para WASM para total independência do cliente
  • O backoff exponencial na reconexão reduz conexões perdidas e elimina recarregamentos manuais de página
  • A compilação AOT reduz o tamanho dos payloads WASM em 40% e o tempo de inicialização em 25%
  • Toda Blazor Web App deve começar com SSR estático como padrão e adicionar interatividade somente onde a experiência do usuário exigir

Comece a praticar!

Teste seus conhecimentos com nossos simuladores de entrevista e testes tecnicos.

Tags

#dotnet
#blazor
#aspnet-core
#webassembly
#full-stack

Compartilhar

Artigos relacionados