Compartilhar via


Pré-renderizar componentes Razor do ASP.NET Core

Observação

Esta não é a versão mais recente deste artigo. Para a versão atual, consulte a versão .NET 9 deste artigo.

Importante

Essas informações relacionam-se ao produto de pré-lançamento, que poderá ser substancialmente modificado antes do lançamento comercial. A Microsoft não oferece nenhuma garantia, explícita ou implícita, quanto às informações fornecidas aqui.

Para a versão atual, consulte a versão .NET 9 deste artigo.

Este artigo explica os cenários de pré-renderização dos componentes Razor para os componentes renderizados pelo servidor nos Blazor Web Apps.

A pré-renderização é o processo de renderizar inicialmente o conteúdo da página no servidor sem habilitar manipuladores de eventos para controles renderizados. O servidor gera a interface do usuário HTML da página o mais rápido possível em resposta à solicitação inicial, o que dá a sensação de que o aplicativo é mais responsivo aos usuários. A pré-renderização também pode melhorar a SEO (Otimização do Mecanismo de Pesquisa) ao renderizar conteúdos de resposta ao HTTP inicial no quais os mecanismos de pesquisa usam para calcular a classificação da página.

Persistência do estado pré-renderizado

Sem a persistência do estado pré-renderizado, há perda do estado usado durante a pré-renderização e ele deve ser recriado quando o aplicativo for totalmente carregado. Se qualquer estado for criado de maneira assíncrona, a interface do usuário poderá piscar à medida que a interface do usuário pré-renderizada for substituída quando o componente for renderizado novamente.

Considere o componente de contador PrerenderedCounter1 a seguir. O componente define um valor de contador aleatório inicial durante a pré-renderização no método OnInitialized do ciclo de vida. Depois que a conexão de SignalR com o cliente é estabelecida, o componente é renderizado novamente e o valor de contagem inicial é substituído quando OnInitialized é executado uma segunda vez.

PrerenderedCounter1.razor:

@page "/prerendered-counter-1"
@rendermode @(new InteractiveServerRenderMode(prerender: true))
@inject ILogger<PrerenderedCounter1> Logger

<PageTitle>Prerendered Counter 1</PageTitle>

<h1>Prerendered Counter 1</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount;

    protected override void OnInitialized()
    {
        currentCount = Random.Shared.Next(100);
        Logger.LogInformation("currentCount set to {Count}", currentCount);
    }

    private void IncrementCount() => currentCount++;
}

Execute o aplicativo e inspecione o log no componente. A seguir está a saída de exemplo:

Observação

Se o aplicativo adotar roteamento interativo e a página for acessada por meio de uma navegação interna aprimorada, a pré-renderização não ocorrerá. Portanto, você deve executar um recarregamento completo da página para que o componente PrerenderedCounter1 veja a saída a seguir. Para obter mais informações, consulte a seção Roteamento interativo e pré-renderização.

info: BlazorSample.Components.Pages.PrerenderedCounter1[0]
currentCount set to 41
info: BlazorSample.Components.Pages.PrerenderedCounter1[0]
currentCount set to 92

A primeira contagem registrada ocorre durante a pré-renderização. A contagem é definida novamente após a pré-renderização quando o componente é renderizado novamente. Há também uma cintilação na interface do usuário quando a contagem é atualizada de 41 para 92.

Para reter o valor inicial do contador durante a pré-renderização, o Blazor dá suporte ao estado persistente em uma página pré-renderizada por meio do serviço PersistentComponentState (e para os componentes incorporados em páginas ou exibições de aplicativos MVC ou Razor Pages, o Auxiliar de Marcas para Persistência do Estado de Componentes).

Para preservar o estado pré-renderizado, decida qual estado será persistido por meio do serviço PersistentComponentState. PersistentComponentState.RegisterOnPersisting registra um retorno de chamada para a persistência do estado do componente antes que o aplicativo seja pausado. O estado é recuperado com a retomada do aplicativo.

O seguinte exemplo demonstra o padrão geral:

  • O espaço reservado {TYPE} representa o tipo de dados a ser persistido.
  • O espaço reservado {TOKEN} é uma cadeia de caracteres de identificador de estado. Considere usar nameof({VARIABLE}), em que o espaço reservado {VARIABLE} é o nome da variável que mantém o estado. Usar nameof() para o identificador de estado evita o uso de uma cadeia de caracteres entre aspas.
@implements IDisposable
@inject PersistentComponentState ApplicationState

...

@code {
    private {TYPE} data;
    private PersistingComponentStateSubscription persistingSubscription;

    protected override async Task OnInitializedAsync()
    {
        persistingSubscription = 
            ApplicationState.RegisterOnPersisting(PersistData);

        if (!ApplicationState.TryTakeFromJson<{TYPE}>(
            "{TOKEN}", out var restored))
        {
            data = await ...;
        }
        else
        {
            data = restored!;
        }
    }

    private Task PersistData()
    {
        ApplicationState.PersistAsJson("{TOKEN}", data);

        return Task.CompletedTask;
    }

    void IDisposable.Dispose()
    {
        persistingSubscription.Dispose();
    }
}

O exemplo de componente de contador a seguir persiste o estado do contador durante a pré-renderização e recupera o estado para inicializar o componente.

PrerenderedCounter2.razor:

@page "/prerendered-counter-2"
@implements IDisposable
@inject ILogger<PrerenderedCounter2> Logger
@inject PersistentComponentState ApplicationState

<PageTitle>Prerendered Counter 2</PageTitle>

<h1>Prerendered Counter 2</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount;
    private PersistingComponentStateSubscription persistingSubscription;

    protected override void OnInitialized()
    {
        persistingSubscription =
            ApplicationState.RegisterOnPersisting(PersistCount);

        if (!ApplicationState.TryTakeFromJson<int>(
            nameof(currentCount), out var restoredCount))
        {
            currentCount = Random.Shared.Next(100);
            Logger.LogInformation("currentCount set to {Count}", currentCount);
        }
        else
        {
            currentCount = restoredCount!;
            Logger.LogInformation("currentCount restored to {Count}", currentCount);
        }
    }

    private Task PersistCount()
    {
        ApplicationState.PersistAsJson(nameof(currentCount), currentCount);

        return Task.CompletedTask;
    }

    void IDisposable.Dispose() => persistingSubscription.Dispose();

    private void IncrementCount() => currentCount++;
}

Quando o componente é executado, a currentCount é definida apenas uma vez durante a pré-renderização. O valor é restaurado quando o componente é renderizado novamente. A seguir está a saída de exemplo:

Observação

Se o aplicativo adotar roteamento interativo e a página for acessada por meio de uma navegação interna aprimorada, a pré-renderização não ocorrerá. Portanto, você deve executar um recarregamento completo da página para que o componente PrerenderedCounter2 veja a saída a seguir. Para obter mais informações, consulte a seção Roteamento interativo e pré-renderização.

info: BlazorSample.Components.Pages.PrerenderedCounter2[0]
currentCount set to 96
info: BlazorSample.Components.Pages.PrerenderedCounter2[0]
currentCount restored to 96

Ao inicializar componentes com o mesmo estado usado durante a pré-renderização, todas as etapas de inicialização dispendiosa só são executadas uma vez. A interface do usuário renderizada também corresponde à interface do usuário pré-renderizada, portanto, nenhuma cintilação ocorre no navegador.

O estado pré-renderizado persistente é transferido para o cliente, onde é usado para restaurar o estado do componente. Durante a renderização do lado do cliente (CSR, InteractiveWebAssembly), os dados são expostos ao navegador e não devem conter informações confidenciais e privadas. Durante a renderização interativa do lado do servidor (SSR interativo), InteractiveServerASP.NET Core Data Protection garante que os dados sejam transferidos com segurança. O InteractiveAuto modo de renderização combina WebAssembly e interatividade do servidor, por isso é necessário considerar a exposição de dados ao navegador, como no caso de CSR.

Componentes inseridos em páginas e exibições (Páginas/MVC Razor)

Para os componentes incorporados em uma página ou em uma exibição de um aplicativo MVC ou Razor Pages, adicione o Auxiliar de Marcas para Persistência do Estado de Componentes com a marca HTML <persist-component-state /> dentro da marca </body> de fechamento do layout do aplicativo. Isso só é necessário em aplicativos MVC e Razor Pages. Para obter mais informações, confira Auxiliar de Marcas para Persistência do Estado de Componentes no ASP.NET Core.

Pages/Shared/_Layout.cshtml:

<body>
    ...

    <persist-component-state />
</body>

Roteamento interativo e pré-renderização

Quando o componente Routes não define um modo de renderização, o aplicativo está usando interatividade e navegação por página/componente. Utilizando a navegação por página/componente, depois que o aplicativo se torna interativo, a navegação interna† é gerenciada por roteamento aprimorado. Neste contexto, †interna significa que o destino da URL do evento de navegação é um ponto de extremidade do Blazor dentro do aplicativo.

O serviço PersistentComponentState funciona apenas na carga inicial da página e não em eventos de navegação de página avançados internos.

Se o aplicativo executar uma navegação completa (não aprimorada) para uma página que utiliza estado do componente persistente, o estado persistido fica disponível para o aplicativo usar quando ele se tornar interativo.

Se um circuito interativo já tiver sido estabelecido e uma navegação aprimorada for executada em uma página utilizando o estado do componente persistente, o estado não será disponibilizado no circuito existente para que o componente use. Não é feita nenhuma pré-renderização para a solicitação de página interna, e o serviço PersistentComponentState não está ciente de que uma navegação aprimorada tenha ocorrido. Não há mecanismo para fornecer atualizações de estado para componentes que já estão em execução em um circuito existente. O motivo disso é que Blazor só dá suporte à passagem de estado do servidor para o cliente no momento em que o runtime é inicializado, não após o runtime ter sido iniciado.

O trabalho adicional na estrutura de Blazor para resolver esse cenário está em consideração para o .NET 10 (novembro de 2025). Para mais informações e discussão da comunidade sobre soluções alternativas sem suporte‡, consulte Suporte para estado de componente persistente em navegações aprimoradas de páginas (dotnet/aspnetcore nº 51584). ‡Soluções alternativas sem suporte não são sancionadas pela Microsoft para uso em aplicativos Blazor. Use pacotes, abordagens e código de terceiros por sua conta e risco.

A desabilitação da navegação aprimorada, que reduz o desempenho, mas também evita o problema de carregar o estado com PersistentComponentState para solicitações de página internas, é abordada em Roteamento e navegação com ASP.NET Core Blazor.

Diretrizes de pré-renderização

As diretrizes de pré-renderização são organizadas na documentação do Blazor por assunto. Os seguintes links abrangem todas as diretrizes de pré-renderização em toda a documentação definidas por assunto: