ASP.NET no .NET 11 Preview 5: novidades e melhorias
O Blazor no .NET 11 deu um salto importante com o Preview 5, a versão de junho de 2026 que concentrou quase todas as novidades do ASP.NET Core no framework de componentes. Formulários, estado, hospedagem WebAssembly e renderização mista receberam melhorias que mudam o dia a dia de quem constrói interfaces com C#.
Neste guia, você vai entender cada mudança, ver o código necessário e saber o que revisar antes de adotar a versão. Além disso, o artigo cobre os ajustes que o preview trouxe para Kestrel e OpenAPI.
Por que o Blazor no .NET 11 Preview 5 importa
Desde o .NET 8, o Blazor permite misturar componentes estáticos e interativos na mesma aplicação. No entanto, essa liberdade sempre teve um custo: vários recursos só funcionavam com um circuito SignalR ativo ou com o runtime WebAssembly carregado.
O Preview 5 ataca justamente essa diferença. Assim, o Blazor no .NET 11 leva validação no cliente, paginação e estado de sessão para páginas renderizadas no servidor, sem exigir interatividade.
Ao mesmo tempo, a versão melhora a experiência de quem publica aplicações WebAssembly standalone. O novo Gateway resolve um problema antigo de rotas client-side no refresh do navegador.
Como toda preview, os nomes de APIs ainda podem mudar. De fato, algumas APIs citadas aqui ganharam outro formato nas versões seguintes, e o texto indica esses casos.
A referência oficial está em What's new in ASP.NET Core in .NET 11, página que a Microsoft atualiza a cada preview.
Formulários mais inteligentes no Blazor no .NET 11
Formulários são a área com mais novidades no Blazor no .NET 11 Preview 5. São três frentes: validação no navegador para SSR, regras assíncronas e mensagens localizadas.
Feedback instantâneo em páginas SSR
Até aqui, um formulário em SSR estático só descobria erros depois do envio. Por isso, o usuário preenchia tudo, clicava em enviar e só então via que o email estava errado.
Agora, formulários SSR que usam DataAnnotationsValidator validam os campos direto no navegador. O servidor renderiza os metadados das regras, e o script do Blazor aplica essas regras no cliente sem round-trip.
Na prática, a experiência fica equivalente à do MVC com unobtrusive validation e à dos componentes interativos. Além disso, o modelo .NET segue como fonte única das regras.
<EditForm Model="Model" Enhance FormName="registration" OnValidSubmit="HandleValidSubmit">
<DataAnnotationsValidator />
<div>
<label for="Email">Email</label>
<InputText @bind-Value="Model!.Email" id="Email" />
<ValidationMessage For="@(() => Model!.Email)" />
</div>
<div>
<label for="Password">Password</label>
<InputText @bind-Value="Model!.Password" id="Password" type="password" />
<ValidationMessage For="@(() => Model!.Password)" />
</div>
<button type="submit" id="submit-btn">Register</button>
</EditForm>
O recurso vem ligado por padrão e atende formulários enhanced e não enhanced. Portanto, quem já usa Data Annotations ganha a melhoria sem tocar no modelo.
Mesmo assim, mantenha a validação no servidor. O navegador melhora a usabilidade, mas a segurança continua dependendo do que o servidor confere.
Validação assíncrona no Blazor no .NET 11
Verificar se um nome de usuário já existe exige uma consulta ao banco ou a uma API. Até então, esse tipo de regra pedia código manual fora do fluxo de validação do EditForm.
Com o Blazor no .NET 11, o submit do EditForm aguarda os validadores assíncronos em qualquer modo de renderização. Nos modos interativos, um componente validador registra tarefas por campo com EditContext.AddValidationTask.
O framework acompanha essas tarefas e cancela as que ficaram obsoletas, por exemplo quando o usuário digita de novo. Além disso, ele informa o andamento com IsValidationPending(field) e IsValidationFaulted(field).
<EditForm EditContext="editContext" OnSubmit="HandleSubmit">
<InputText @bind-Value="model.Username" />
@if (editContext.IsValidationPending(() => model.Username))
{
<!-- Mostra o aviso enquanto a checagem assíncrona roda -->
<span>Checking availability...</span>
}
<ValidationMessage For="() => model.Username" />
<button type="submit">Register</button>
</EditForm>
O Preview 5 entrega apenas os blocos de construção. A integração completa com DataAnnotationsValidator dependia de novas APIs assíncronas de DataAnnotations, previstas para depois.
Segundo a documentação atual, essas APIs chegaram como AsyncValidationAttribute e IAsyncValidatableObject. Também vale notar que o registro por campo passou a se chamar EditContext.RegisterAsyncFieldValidator em versões posteriores.
Mensagens de erro em vários idiomas
O Blazor no .NET 11 também trouxe localização de primeira classe para mensagens de validação e nomes de propriedades. A novidade vale para formulários Blazor e para endpoints de Minimal API.
Por padrão, as traduções vêm de arquivos RESX por idioma, publicados com o assembly. O registro acontece em uma linha:
builder.Services.AddValidation()
.AddValidationLocalization<ValidationMessages>();
// Procura ValidationMessages.en.resx, ValidationMessages.pt-BR.resx, ...
O valor de ErrorMessage em cada atributo vira a chave de busca no arquivo de recursos. Dessa forma, o modelo guarda só a chave, e o texto final depende da cultura ativa.
[ValidatableType]
public class ContactModel
{
[Required(ErrorMessage = "RequiredField")]
[EmailAddress(ErrorMessage = "InvalidEmail")]
[Display(Name = "ContactEmail")]
public string? Email { get; set; }
}
Quem guarda traduções em banco de dados ou JSON pode registrar uma implementação própria de IStringLocalizerFactory. Nesse caso, a implementação do usuário tem precedência sobre o RESX.
Para não repetir chaves em todos os atributos, existe ainda uma estratégia programática:
builder.Services.AddValidation()
.AddValidationLocalization<ValidationMessages>(options =>
{
// Sem ErrorMessage, a chave vira "{NomeDoAtributo}_Error"
options.ErrorMessageKeyProvider = ctx =>
ctx.Attribute.ErrorMessage ?? $"{ctx.Attribute.GetType().Name}_Error";
});
Em projetos com dezenas de modelos, essa centralização reduz duplicação e facilita a inclusão de idiomas. Contudo, versões posteriores tornaram a localização nativa com AddLocalization e AddValidation, então revise o registro ao atualizar.
QuickGrid com ordenação e paginação via URL
Antes do Blazor no .NET 11, o QuickGrid sempre precisou de interatividade para ordenar colunas e trocar de página. No Preview 5, esses recursos passam a funcionar em páginas SSR estáticas.
O segredo está na URL. Sem modo interativo, cabeçalhos ordenáveis e o paginador viram links que gravam o estado na query string, em vez de depender de @onclick.
@page "/orders"
@using Microsoft.AspNetCore.Components.QuickGrid
<QuickGrid Items="orders.AsQueryable()" Pagination="pagination">
<PropertyColumn Property="@(o => o.Id)" Sortable="true" />
<PropertyColumn Property="@(o => o.Customer)" Sortable="true" />
<PropertyColumn Property="@(o => o.Total)" Sortable="true" />
</QuickGrid>
<Paginator State="pagination" />
@code {
// 20 itens por página, com estado guardado na URL
private readonly PaginationState pagination = new() { ItemsPerPage = 20 };
private readonly List<Order> orders = OrderRepository.GetOrders();
}
Como bônus, o usuário pode compartilhar o link de uma página específica e usar o botão voltar do navegador. A documentação cita parâmetros como page, sort e direction.
O comportamento vem ativo por padrão. Para voltar aos botões antigos, desligue o switch Microsoft.AspNetCore.Components.QuickGrid.EnableUrlBasedQuickGridNavigationAndSorting:
// Restaura <button> com @onclick, o que exige modo interativo
AppContext.SetSwitch(
"Microsoft.AspNetCore.Components.QuickGrid.EnableUrlBasedQuickGridNavigationAndSorting",
false);
Fique atento ao CSS. Como o elemento muda de <button> para <a>, estilos que usam seletores de elemento podem quebrar.
Estado entre servidor e cliente no Blazor no .NET 11
Duas novidades do Blazor no .NET 11 tratam de estado. Uma alinha a cultura entre a pré-renderização e o cliente, enquanto a outra leva a sessão HTTP para dentro dos componentes SSR.
Mesma cultura na pré-renderização e no cliente
Imagine uma página que mostra valores em reais. Antes, o servidor pré-renderizava com a cultura dele e, depois da hidratação, o cliente refazia a tela com outra formatação.
Agora, aplicações Blazor WebAssembly com pré-renderização persistem o CurrentCulture e o CurrentUICulture do servidor no estado do componente. Em seguida, o cliente aplica essa cultura antes de carregar os assemblies satélite.
Com isso, datas, moedas e números aparecem iguais nas duas etapas. O comportamento vem ligado por padrão para componentes WebAssembly interativos.
Se a sua aplicação deixa o cliente escolher a cultura, desligue a opção:
builder.Services.AddRazorComponents()
.AddInteractiveWebAssemblyComponents(options =>
{
// O cliente define a cultura sozinho
options.UseCultureFromServer = false;
});
Sessão HTTP direto no componente
O atributo [SupplyParameterFromSession] segue o mesmo modelo de [SupplyParameterFromQuery] e [SupplyParameterFromForm]. Ou seja, uma propriedade do componente lê e grava um valor da sessão HTTP sem código extra.
Isso serve bem para o ID de um carrinho ou para o passo atual de um formulário em várias etapas. O framework serializa os valores com System.Text.Json e grava tudo antes de enviar a resposta.
@page "/checkout"
<p>Current step: @CurrentStep</p>
<EditForm Model="Input" FormName="checkout" OnSubmit="NextStep">
<button type="submit">Next</button>
</EditForm>
@code {
// Lido e gravado na sessão com a chave "checkout-step"
[SupplyParameterFromSession(Name = "checkout-step")]
public int CurrentStep { get; set; }
private object Input { get; } = new();
private void NextStep() => CurrentStep++;
}
Para funcionar, registre o cache, a sessão e o middleware no Program.cs:
builder.Services.AddDistributedMemoryCache();
builder.Services.AddSession();
builder.Services.AddRazorComponents();
var app = builder.Build();
app.UseSession();
Ao contrário do TempData, o valor não desaparece depois da primeira leitura. Ele fica disponível enquanto a sessão existir.
O novo Gateway do Blazor no .NET 11
Aplicações Blazor WebAssembly standalone ganharam um novo servidor com o Blazor no .NET 11. O pacote Microsoft.AspNetCore.Components.Gateway substitui o Microsoft.AspNetCore.Components.WebAssembly.DevServer.
A diferença é estrutural. Enquanto o DevServer era uma ferramenta de arquivos estáticos, o Gateway é um host ASP.NET Core completo e leve, pensado para desenvolvimento e produção.
Por isso, o fallback SPA vem embutido. Qualquer requisição que não aponta para um arquivo estático cai no index.html, e uma rota como /orders/42 funciona no refresh e no acesso direto.
Em um projeto existente, basta ajustar as referências de pacote:
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="11.0.0-preview.5.26302.115" />
<PackageReference Include="Microsoft.AspNetCore.Components.Gateway" Version="11.0.0-preview.5.26302.115" PrivateAssets="all" />
</ItemGroup>
Projetos novos criados com o template atualizado já trazem o Gateway. Além disso, a documentação informa que o inspectUri do launchSettings.json deixa de ser necessário.
Conteúdo filho entre modos de renderização
Passar ChildContent de uma página SSR para um componente com @rendermode interativo gerava uma InvalidOperationException. O motivo era simples: RenderFragment é um delegate e não atravessava a fronteira entre os modos.
No Blazor no .NET 11 Preview 5, o framework pré-renderiza o fragmento no servidor, captura a árvore resultante e reidrata essa árvore dentro do componente interativo.
<MyComponent @rendermode="InteractiveServer">
<p>This content is rendered as SSR and projected into the interactive component.</p>
</MyComponent>
O suporte cobre ChildContent e outros RenderFragment não genéricos. Assim, layouts que embrulham componentes interativos com conteúdo estático ficam bem mais simples de montar.
Além do Blazor: Kestrel, OpenAPI e correções
O preview não ficou restrito aos componentes. Kestrel e OpenAPI também receberam ajustes, além de uma lista de correções de bugs.
Proteção contra trailer headers incompletos
O Kestrel agora aplica o RequestHeadersTimeout aos trailer headers fragmentados de HTTP/2 e HTTP/3. Dessa forma, uma conexão não fica aberta para sempre esperando um frame HEADERS que nunca termina.
builder.WebHost.ConfigureKestrel(options =>
{
// O mesmo limite protege headers iniciais e trailers
options.Limits.RequestHeadersTimeout = TimeSpan.FromSeconds(10);
});
Em servidores com muita concorrência, isso evita que clientes maliciosos ou com bugs consumam recursos indefinidamente.
Schemas OpenAPI mais fiéis
Parâmetros enum fora do corpo agora mantêm os nomes originais dos membros C#. Isso vale mesmo quando o JsonStringEnumConverter define uma política de nomenclatura, porque query, route, header e form usam Enum.TryParse.
builder.Services.ConfigureHttpJsonOptions(options =>
{
options.SerializerOptions.Converters.Add(
new JsonStringEnumConverter(JsonNamingPolicy.KebabCaseLower));
});
app.MapGet("/orders", (OrderStatus status) => Results.Ok(status));
Nesse exemplo, o schema do corpo mostra OrderStatus.PendingReview como pending-review. Já o parâmetro de query aparece como PendingReview, que é o valor que o binding aceita.
Os schemas de arrays também ganharam IDs válidos, como stringArray e TodoArray. Por fim, Minimal APIs aceitam vários Produces<T>() para o mesmo status code, e controllers aceitam vários [ProducesResponseType].
Correções que merecem atenção
No Blazor no .NET 11, a equipe corrigiu uma falha ao renderizar um componente interativo a partir de um layout durante a navegação enhanced. Também incluiu anotações StringSyntaxAttribute.DateTimeFormat nos overloads de DateTimeOffset do BindConverter.
Em Data Protection, o time resolveu a starvation do thread pool no KeyRingProvider durante a inicialização a frio. O problema surgia quando muitos chamadores pediam chaves antes de o key ring entrar em cache.
No Kestrel, mensagens HTTP/2 e HTTP/3 com headers específicos de conexão passam a contar como malformadas, conforme os RFCs 9113 e 9114. Além disso, o servidor fecha a conexão após uma requisição com Content-Length e Transfer-Encoding juntos, como pede o RFC 9112.
Em Minimal APIs, structs opcionais não anuláveis com = default na query deixaram de lançar exceção. Também, application/problem+json e application/problem+xml seguem como tipos preferidos quando o ProducesAttribute define outro tipo.
Como as novidades se combinam no Blazor no .NET 11
Vistas isoladamente, as mudanças parecem pequenas. No entanto, o Blazor no .NET 11 fica bem mais interessante quando você combina os recursos em um mesmo fluxo.
Pense em uma loja com uma página de pedidos e um checkout em várias etapas, tudo em SSR estático. Antes, cada um desses pontos exigia interatividade ou código extra.
Com o Preview 5, a lista de pedidos usa o QuickGrid com ordenação e paginação pela URL. Assim, o cliente compartilha o link da página três da lista e o colega abre exatamente a mesma visão.
Em seguida, o checkout guarda a etapa atual com [SupplyParameterFromSession]. Dessa forma, o progresso sobrevive entre requisições sem banco de dados nem cookies manuais.
Cada etapa do checkout valida os campos no navegador com DataAnnotationsValidator. Enquanto isso, o servidor repete a validação no envio, como manda a boa prática.
Por fim, se uma parte da tela precisar de interatividade, como um resumo do carrinho, o componente interativo recebe ChildContent vindo da página SSR. Ou seja, o Blazor no .NET 11 permite manter quase tudo estático e ligar a interatividade só onde ela agrega valor.
Checklist para adotar o Blazor no .NET 11
Antes de testar o Blazor no .NET 11 Preview 5 em um projeto real, vale revisar alguns pontos levantados pelas próprias mudanças:
- Revise o CSS do
QuickGrid, porque botões viraram links. - Troque o DevServer pelo Gateway nos projetos WebAssembly standalone.
- Registre
AddSessioneUseSessionantes de usar[SupplyParameterFromSession]. - Confira se o cliente deve herdar a cultura do servidor.
- Mantenha a validação no servidor, mesmo com o feedback no navegador.
Também é prudente testar em um projeto separado, com o SDK de preview fixado em um global.json. Assim, as aplicações de produção continuam na versão estável.
Para acompanhar a evolução seguinte, a análise do ASP.NET Core no .NET 11 Preview 7 mostra como várias dessas APIs amadureceram. Já o guia de Blazor AI components explora outra frente nova do framework.
Conclusão
O Preview 5 deixa claro para onde vai o Blazor no .NET 11: menos distância entre páginas estáticas e componentes interativos. Validação no cliente, QuickGrid via URL e sessão declarativa funcionam agora sem circuito nem WebAssembly.
Ao mesmo tempo, no Blazor no .NET 11, o Gateway e a passagem de ChildContent entre render modes mostram uma plataforma mais madura. Portanto, equipes que usam renderização mista têm bons motivos para acompanhar de perto as próximas previews.
FAQ
O Blazor no .NET 11 Preview 5 já pode ir para produção?
Previews servem para avaliação e podem mudar até a versão final. Por isso, use em projetos de teste e acompanhe as notas de cada lançamento.
Preciso mudar meus modelos para ter validação no cliente em SSR?
Não. Basta o formulário usar DataAnnotationsValidator, e as Data Annotations existentes passam a valer no navegador.
O [SupplyParameterFromSession] funciona em componentes interativos?
O atributo foi pensado para o Blazor SSR, no mesmo escopo de [SupplyParameterFromQuery] e [SupplyParameterFromForm].
O Gateway substitui o DevServer em produção?
Sim. Como é um host ASP.NET Core completo com fallback SPA, ele atende desenvolvimento e produção.
Fragmentos genéricos também atravessam render modes?
No Preview 5, o suporte cobre apenas ChildContent e outros RenderFragment não genéricos.