Modos de renderização Blazor do ASP.NET Core

Este artigo explica o controle da renderização de componentes Razor em Blazor aplicativos Web, seja em tempo de compilação ou runtime.

Essas diretrizes não se aplicam a aplicativos autônomos Blazor WebAssembly. Blazor WebAssembly os aplicativos são renderizados apenas no cliente por meio de um tempo de execução baseado em WebAssembly do lado do cliente e não têm conceito de modo de renderização. Se um modo de renderização for aplicado a um componente em um aplicativo Blazor WebAssembly, a designação do modo de renderização não terá influência na renderização do componente.

Modos de renderização

Cada componente em um Blazor Aplicativos Web adota um modo de renderização para determinar o modelo de hospedagem que utiliza, em que é renderizado e se é ou não interativo.

A tabela a seguir mostra os modos de renderização disponíveis para a renderização de componentes Razor em um aplicativo Web Blazor. Para aplicar um modo de renderização a um componente, utilize a diretiva @rendermode na instância do componente ou na definição do componente. Mais adiante neste artigo, são mostrados exemplos para cada cenário de modo de renderização.

Nome Descrição Local de renderização Interativo
Servidor estático Renderização do lado do servidor estática (SSR estática) Servidor Não
Servidor interativo Renderização interativa no lado do servidor (SSR interativo) usando Blazor Server. Servidor Sim
WebAssembly interativo Renderização do lado do cliente (CSR) usando Blazor WebAssembly†. Cliente Sim
Auto interativo SSR interativa usando Blazor Server inicialmente e, em seguida, CSR em visitas subsequentes depois que o pacote Blazor é baixado. Servidor, depois o cliente Sim

†A renderização do lado do cliente (CSR) é considerada interativa. A "renderização do lado do cliente interativa" e a "CSR interativa" não são usadas pelo setor ou na documentação Blazor.

A pré-renderização estão habilitada por padrão para componentes interativos. As diretrizes para controlar a pré-renderização são fornecidas mais adiante neste artigo. Para ver a terminologia geral do setor sobre conceitos de renderização de cliente e servidor, confira Conceitos básicos do Blazor do ASP.NET Core.

Os exemplos a seguir demonstram a configuração do modo de renderização do componente com alguns recursos básicos do componente Razor.

Para testar os comportamentos do modo de renderização localmente, você pode colocar os seguintes componentes em um aplicativo criado a partir do modelo de projeto de Blazor Aplicativo Web. Quando criar o aplicativo, selecione as opções dos menus suspensos (Visual Studio) ou aplique as opções da CLI (CLI do .NET ) para habilitar a interatividade do lado do servidor e do lado do cliente. Para obter diretrizes sobre como criar um Blazor Aplicativo Web, consulte Ferramentas para o ASP.NET Core Blazor.

Habilitar o suporte a modos de renderização interativos

Um Aplicativo Web Blazor deve ser configurado para dar suporte a modos de renderização interativos. As seguintes extensões são aplicadas automaticamente aos aplicativos criados a partir do modelo de projeto de Blazor Aplicativo Web durante a criação do aplicativo. Os componentes individuais ainda são obrigados a declarar seu modo de renderização de acordo com a seção Modos de Renderização depois que os pontos de extremidade e serviços do componente forem configurados no arquivo Program do aplicativo.

Os serviços para componentes Razor são adicionados chamando AddRazorComponents.

Extensões do construtor de componentes:

MapRazorComponents descobre os componentes disponíveis e especifica o componente raiz do aplicativo (o primeiro componente carregado), que por padrão é o componente App (App.razor).

Extensões do construtor de convenções de ponto de extremidade:

Observação

Para obter orientação sobre o posicionamento da API nos exemplos a seguir, inspecione o arquivo Program de um aplicativo gerado a partir do modelo de projeto Blazor modelo de projeto do aplicativo Web. Para obter diretrizes sobre como criar um Blazor Aplicativo Web, consulte Ferramentas para o ASP.NET Core Blazor.

Exemplo 1: o arquivo da API Program a seguir adiciona serviços e configuração para habilitar a SSR interativa:

builder.Services.AddRazorComponents()
    .AddInteractiveServerComponents();
app.MapRazorComponents<App>()
    .AddInteractiveServerRenderMode();

Exemplo 2: a API do arquivo Program a seguir adiciona serviços e configuração para habilitar o modo de renderização do WebAssembly Interativo:

builder.Services.AddRazorComponents()
    .AddInteractiveWebAssemblyComponents();
app.MapRazorComponents<App>()
    .AddInteractiveWebAssemblyRenderMode();

Exemplo 3: a seguinte API do arquivo Program adiciona serviços e configurações para habilitar os modos de renderização Auto Interativo, do WebAssembly Interativo e do Servidor Interativo:

builder.Services.AddRazorComponents()
    .AddInteractiveServerComponents()
    .AddInteractiveWebAssemblyComponents();
app.MapRazorComponents<App>()
    .AddInteractiveServerRenderMode()
    .AddInteractiveWebAssemblyRenderMode();

Blazor usa o modelo de hospedagem Blazor WebAssembly para fazer download e executar componentes que utilizam o modo de renderização WebAssembly Interativo. É obrigatório um projeto cliente separado para configurar a hospedagem Blazor WebAssembly para esses componentes. O projeto cliente contém o código de inicialização do host Blazor WebAssembly e configura o runtime do .NET para execução em um navegador. O modelo de aplicativo Web Blazor adiciona esse projeto cliente quando você seleciona a opção de habilitar a interatividade do WebAssembly. Todos os componentes que utilizam o modo de renderização do WebAssembly Interativo devem ser criados a partir do projeto cliente, para que sejam incluídos no lote de aplicativos baixado.

Aplicar um modo de renderização a uma instância de componente

Para aplicar um modo de renderização a uma instância de componente, use o atributo @rendermodeRazor da diretiva em que o componente é utilizado.

No exemplo a seguir, a renderização interativa do lado do servidor (SSR interativa) é aplicada à instância do componente Dialog:

<Dialog @rendermode="InteractiveServer" />

Observação

Os modelos do Blazor incluem uma diretiva estática using para RenderMode no arquivo _Imports do aplicativo (Components/_Imports.razor) para sintaxe mais curta @rendermode:

@using static Microsoft.AspNetCore.Components.Web.RenderMode

Sem a diretiva anterior, os componentes devem especificar a classe estática RenderMode na sintaxe @rendermode:

<Dialog @rendermode="RenderMode.InteractiveServer" />

Você também pode referenciar instâncias do modo de renderização personalizada instanciadas diretamente com a configuração personalizada. Para obter mais informações, confira a seção Modos de renderização de abreviação personalizados mais adiante neste artigo.

Aplicar um modo de renderização a uma definição de componente

Para especificar o modo de renderização de um componente como parte da sua definição, utilize a diretiva @rendermodeRazor e o atributo de modo de renderização correspondente.

@page "..."
@rendermode InteractiveServer

A aplicação de um modo de renderização a uma definição de componente é comumente utilizada quando se aplica um modo de renderização a uma página específica. Por padrão, as páginas roteáveis utilizam o mesmo modo de renderização que o componente Router que renderizou a página.

Tecnicamente, @rendermode é uma Razordiretiva e um Razoratributo de diretiva. A semântica é semelhante, mas existem diferenças. A diretiva @rendermode está na definição do componente, de modo que a instância do modo de renderização referenciada deve ser estática. O atributo de diretiva @rendermode pode receber qualquer instância de modo de renderização.

Observação

Os autores de componentes devem evitar acoplar a implementação de um componente a um modo de renderização específico. Em vez disso, os autores de componentes normalmente devem projetar componentes para dar suporte a qualquer modo de renderização ou modelo de hospedagem. A implementação de um componente deve evitar suposições sobre o local em que ele está sendo executado (servidor ou cliente) e deve se degradar suavemente quando renderizado estaticamente. A especificação do modo de renderização na definição do componente pode ser necessária se o componente não for diretamente instanciado (como no caso de um componente de página roteável) ou para especificar um modo de renderização para todas as instâncias do componente.

Aplicar um modo de renderização a todo o aplicativo

Para definir o modo de renderização de todo o aplicativo, indique o modo de renderização no componente interativo de nível mais alto na hierarquia de componentes do aplicativo que não é um componente raiz.

Observação

Não há suporte para tornar um componente raiz interativo, como o componente App. Portanto, o modo de renderização de todo o aplicativo não pode ser definido diretamente pelo componente App.

Para aplicativos com base no modelo de projeto do Aplicativo Web Blazor, um modo de renderização atribuído a todo o aplicativo normalmente é especificado, onde o componente Routes é usado no componente App (Components/App.razor):

<Routes @rendermode="InteractiveServer" />

O componente Router propaga seu modo de renderização para as páginas que roteia.

Normalmente, você também deve definir o mesmo modo de renderização interativo no componente HeadOutlet, que também é encontrado no componente App de um aplicativo Web Blazor gerado a partir do modelo do projeto:

<HeadOutlet @rendermode="InteractiveServer" />

Para aplicativos que adotam um modo de renderização interativa do lado do cliente (WebAssembly ou renderização Automática) e habilitam o modo de renderização para todo o aplicativo por meio do componente Routes:

  • Coloque ou mova os arquivos de layout e navegação da pasta Components/Layout do aplicativo de servidor para a pasta Layout do projeto .Client. Crie uma pasta Layout no projeto .Client se ela não existir.
  • Coloque ou mova os componentes da pasta do aplicativo de servidor Components/Pages para a pasta Pages do projeto .Client. Crie uma pasta Pages no projeto .Client se ela não existir.
  • Coloque ou mova o componente Routes da pasta Components do aplicativo de servidor para a pasta raiz do projeto .Client.

Para habilitar a interatividade global ao criar um aplicativo Web Blazor:

  • Visual Studio: defina a lista suspensa Local de interatividade como Global.
  • CLI do .NET: use a opção -ai|--all-interactive.

Para obter mais informações, confira Ferramentas para ASP.NET Core Blazor.

Aplicar um modo de renderização programaticamente

Propriedades e campos podem atribuir um modo de renderização.

O segundo método descrito nesta seção, que é configurar o modo de renderização por instância de componente, é particularmente útil quando as especificações do seu aplicativo exigem um dos seguintes cenários:

  • Você possui uma área (pasta) no aplicativo com componentes que precisam adotar a renderização estática do lado do servidor (SSR estática) e serem executados somente no servidor. O aplicativo gerencia o modo de renderização de forma global, ajustando o modo de renderização no componente Routes dentro do componente App, baseando-se no caminho para a pasta.
  • Você tem componentes distribuídos pelo aplicativo em diferentes locais (não em uma única pasta) que precisam adotar a SSR estática e serem executados somente no servidor. O aplicativo gerencia o modo de renderização individualmente para cada componente, configurando o modo de renderização com a diretiva @rendermode nas instâncias dos componentes. A reflexão é utilizada no componente App para estabelecer o modo de renderização no componente Routes.

Em ambos os casos, o componente que precisa adotar a SSR estática também deve forçar um recarregamento completo da página.

Os dois cenários mencionados são abordados com exemplos na seção Controle detalhado dos modos de renderização mais adiante neste artigo. As duas subseções a seguir se concentram em métodos básicos para definir o modo de renderização.

Definir o modo de renderização pela definição do componente

Uma definição de componente pode definir um modo de renderização por meio de um campo privado:

@rendermode renderModeForPage

...

@code {
    private static IComponentRenderMode renderModeForPage = InteractiveServer;
}

Definir o modo de renderização pela instância do componente

O exemplo a seguir aplica a renderização interativa do lado do servidor (SSR interativa) a qualquer solicitação.

<Routes @rendermode="RenderModeForPage" />

...

@code {
    private IComponentRenderMode? RenderModeForPage => InteractiveServer;
}

Informações adicionais sobre a propagação do modo de renderização são fornecidas na seção Propagação do modo de renderização mais adiante neste artigo. A seção Controle detalhado dos modos de renderização demonstra como utilizar o método anterior para adotar a SSR estática em áreas específicas do aplicativo (pastas) ou para componentes específicos espalhados pelo aplicativo, com atribuições de modo de renderização para cada componente.

Pré-renderização

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.

A pré-renderização estão habilitada por padrão para componentes interativos.

Para desabilitar a pré-geração de uma instância de componente, passe o sinalizador prerender com um valor para o modo de renderização false:

  • <... @rendermode="new InteractiveServerRenderMode(prerender: false)" />
  • <... @rendermode="new InteractiveWebAssemblyRenderMode(prerender: false)" />
  • <... @rendermode="new InteractiveAutoRenderMode(prerender: false)" />

Para desabilitar a pré-renderização em uma definição de componente:

  • @rendermode @(new InteractiveServerRenderMode(prerender: false))
  • @rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))
  • @rendermode @(new InteractiveAutoRenderMode(prerender: false))

Para desabilitar a pré-renderização de todo o aplicativo, indique o modo de renderização no componente interativo de nível mais alto na hierarquia de componentes do aplicativo que não é um componente raiz.

Para aplicativos com base no modelo de projeto do aplicativo Web Blazor, um modo de renderização atribuído a todo o aplicativo é especificado onde o componente Routes é usado no componente App (Components/App.razor). O exemplo a seguir define o modo de renderização do aplicativo como Servidor Interativo com a pré-renderização desabilitada:

<Routes @rendermode="new InteractiveServerRenderMode(prerender: false)" />

Além disso, desabilite a pré-renderização para o componente HeadOutlet no componente App:

<HeadOutlet @rendermode="new InteractiveServerRenderMode(prerender: false)" />

Não há suporte para tornar um componente raiz, como o componente App, interativo com a diretiva @rendermode na parte superior do arquivo de definição do componente raiz (.razor). Portanto, a pré-renderização não pode ser desabilitada diretamente pelo componente App.

Renderização do lado do servidor estática (SSR estática)

Por padrão, os componentes usam renderização estática no lado do servidor (SSR estático). O componente é renderizado para o streaming de resposta e a interatividade não é habilitada.

No exemplo a seguir, não há designação para o modo de renderização do componente, portanto o componente herda o modo de renderização de seu pai. Como nenhum componente ancestral especifica um modo de renderização, o componente a seguir é renderizado estaticamente no servidor. O botão não é interativo e não chama o método UpdateMessage quando selecionado. O valor de message não é alterado, e o componente não é renderizado novamente em resposta aos eventos da interface do usuário.

RenderMode1.razor:

@page "/render-mode-1"

<button @onclick="UpdateMessage">Click me</button> @message

@code {
    private string message = "Not updated yet.";

    private void UpdateMessage()
    {
        message = "Somebody updated me!";
    }
}

Se estiver usando o componente anterior localmente em um aplicativo Web Blazor, coloque o componente na pasta do projeto do servidor Components/Pages. O projeto do servidor é o projeto da solução com um nome que não termina em .Client. Quando o aplicativo estiver em execução, navegue até /render-mode-1 na barra de endereços do navegador.

Durante o SSR estático, Razor as solicitações de páginas de componentes são processadas pelo processamento de solicitações de pipeline de middleware ASP.NET Core do lado do servidor para roteamento e autorização. Recursos Blazor dedicados para roteamento e autorização não estão operacionais porque Razor os componentes não são renderizados durante o processamento de solicitação no lado do servidor. Blazor Os recursos do roteador no componente Routes que não estão disponíveis durante o SSR estático incluem a exibição:

Se o aplicativo exibir interatividade no nível raiz, o processamento de solicitação do ASP.NET Core no lado do servidor não será envolvido após o SSR estático inicial, o que significa que os recursos Blazor anteriores funcionam conforme o esperado.

A navegação aprimorada com SSR estático requer atenção especial ao carregar o JavaScript. Para obter mais informações, confira JavaScript do ASP.NET Core Blazor com renderização estática do lado do servidor (SSR estática).

Renderização do lado do servidor interativa (SSR interativa)

A renderização interativa do lado do servidor (SSR interativa) renderiza o componente interativamente do servidor usando Blazor Server. As interações do usuário são tratadas por meio de uma conexão em tempo real com o navegador. A conexão de circuito é estabelecida quando o componente Servidor é renderizado.

No exemplo a seguir, o modo de renderização é definido como SSR interativa adicionando @rendermode InteractiveServer à definição do componente. O botão chama o método UpdateMessage quando selecionado. O valor de message é alterado, e o componente é renderizado novamente para atualizar a mensagem na interface do usuário.

RenderMode2.razor:

@page "/render-mode-2"
@rendermode InteractiveServer

<button @onclick="UpdateMessage">Click me</button> @message

@code {
    private string message = "Not updated yet.";

    private void UpdateMessage()
    {
        message = "Somebody updated me!";
    }
}

Se estiver usando o componente anterior localmente em um aplicativo Web Blazor, coloque o componente na pasta do projeto do servidor Components/Pages. O projeto do servidor é o projeto da solução com um nome que não termina em .Client. Quando o aplicativo estiver em execução, navegue até /render-mode-2 na barra de endereços do navegador.

Renderização do lado do cliente (CSR)

A renderização do lado do cliente (CSR) renderiza o componente interativamente no cliente usando Blazor WebAssembly. O runtime do .NET e o lote de aplicativos são baixados e armazenados em cache quando o componente do WebAssembly é renderizado inicialmente. Os componentes que utilizam CSR devem ser criados em um projeto cliente separado que configure o host Blazor WebAssembly.

No exemplo a seguir, o modo de renderização esta definido como CSR com @rendermode InteractiveWebAssembly. O botão chama o método UpdateMessage quando selecionado. O valor de message é alterado, e o componente é renderizado novamente para atualizar a mensagem na interface do usuário.

RenderMode3.razor:

@page "/render-mode-3"
@rendermode InteractiveWebAssembly

<button @onclick="UpdateMessage">Click me</button> @message

@code {
    private string message = "Not updated yet.";

    private void UpdateMessage()
    {
        message = "Somebody updated me!";
    }
}

Se estiver usando o componente anterior localmente em um aplicativo Web Blazor, coloque o componente na pasta Pages do projeto do cliente. O projeto do cliente é o projeto da solução com um nome que termina em .Client. Quando o aplicativo estiver em execução, navegue até /render-mode-3 na barra de endereços do navegador.

Renderização automática (Auto)

A Renderização Automática (Auto) determina como renderizar o componente em runtime. O componente é inicialmente renderizado do lado do servidor com interatividade utilizando o modelo de hospedagem Blazor Server. O runtime do .NET e o lote de aplicativos são baixados para o cliente em segundo plano e armazenados em cache para que possam ser utilizados em visitas futuras.

O Modo de renderização automática nunca altera dinamicamente o modo de renderização de um componente já presente na página. O modo de renderização automática toma uma decisão inicial sobre qual tipo de interatividade usar para um componente, depois o componente mantém esse tipo de interatividade enquanto está na página. Um fator nessa decisão inicial é considerar se já existem componentes na página com interatividade entre WebAssembly/Servidor. O modo automático prefere selecionar um modo de renderização que corresponda ao modo de renderização dos componentes interativos existentes. A razão pela qual o modo Automático prefere usar um modo de interatividade existente é evitar a introdução de um novo tempo de execução interativo que não compartilhe o estado com o runtime existente.

Os componentes que utilizam o modo de renderização automática devem ser criados a partir de um projeto cliente separado que configure o host Blazor WebAssembly.

No exemplo a seguir, o componente é interativo durante todo o processo. O botão chama o método UpdateMessage quando selecionado. O valor de message é alterado, e o componente é renderizado novamente para atualizar a mensagem na interface do usuário. Inicialmente, o componente é renderizado interativamente a partir do servidor, mas nas visitas subsequentes ele é renderizado a partir do cliente depois que o runtime do .NET e o lote de aplicativos são baixados e armazenados em cache.

RenderMode4.razor:

@page "/render-mode-4"
@rendermode InteractiveAuto

<button @onclick="UpdateMessage">Click me</button> @message

@code {
    private string message = "Not updated yet.";

    private void UpdateMessage()
    {
        message = "Somebody updated me!";
    }
}

Se estiver usando o componente anterior localmente em um aplicativo Web Blazor, coloque o componente na pasta Pages do projeto do cliente. O projeto do cliente é o projeto da solução com um nome que termina em .Client. Quando o aplicativo estiver em execução, navegue até /render-mode-4 na barra de endereços do navegador.

Propagação do modo de renderização

Os modos de renderização se propagam pela hierarquia de componentes.

Regras para aplicação dose modos de renderização:

  • O modo de renderização padrão é Estático.
  • Os modos de renderização Servidor Interativo (InteractiveServer), WebAssembly Interativo (InteractiveWebAssembly) e Auto Interativo (InteractiveAuto) podem ser usados ​​com um componente, inclusive usando diferentes modos de renderização para componentes irmãos.
  • Não é possível alternar para um modo de renderização interativo diferente em um componente filho. Por exemplo, um componente Servidor não pode ser filho de um componente WebAssembly.
  • Os parâmetros passados para um componente filho interativo a partir de um pai estático devem ser JSON serializáveis. Isso significa que você não pode passar fragmentos de renderização ou conteúdo filho de um componente pai Estático para um componente filho Interativo.

Os exemplos a seguir usam um componente SharedMessage que não é roteável, nem uma página. O componente SharedMessage agnóstico ao modo de renderização não aplica um modo de renderização com uma diretiva @attribute. Se estiver testando esses cenários com um Aplicativo Web Blazor, coloque o componente a seguir na pasta Components do aplicativo.

SharedMessage.razor:

<p>@Greeting</p>

<button @onclick="UpdateMessage">Click me</button> @message

<p>@ChildContent</p>

@code {
    private string message = "Not updated yet.";

    [Parameter]
    public RenderFragment? ChildContent { get; set; }

    [Parameter]
    public string Greeting { get; set; } = "Hello!";

    private void UpdateMessage()
    {
        message = "Somebody updated me!";
    }
}

Herança do modo de renderização

Se o componente SharedMessage for colocado em um componente pai renderizado estaticamente, o componente SharedMessage também será renderizado estaticamente e não será interativo. O botão não chama UpdateMessage e a mensagem não é atualizada.

RenderMode5.razor:

@page "/render-mode-5"

<SharedMessage />

Se o componente SharedMessage for colocado em um componente que define o modo de renderização, ele herdará o modo de renderização aplicado.

No exemplo a seguir, o componente SharedMessage é interativo em uma conexão SignalR com o cliente. O botão chama UpdateMessage e a mensagem é atualizada.

RenderMode6.razor:

@page "/render-mode-6"
@rendermode InteractiveServer

<SharedMessage />

Componentes filhos com diferentes modos de renderização

No exemplo a seguir, ambos os componentes SharedMessage são pré-renderizados (por padrão) e aparecem quando a página é exibida no navegador.

  • O primeiro componente SharedMessage com renderização interativa do lado do servidor (SSR interativa) é interativo depois que o circuito SignalR é estabelecido.
  • O segundo componente SharedMessage com renderização do lado do cliente é interativo após o download do lote de aplicativos Blazor e o runtime do .NET estar ativo no cliente.

RenderMode7.razor:

@page "/render-mode-7"

<SharedMessage @rendermode="InteractiveServer" />
<SharedMessage @rendermode="InteractiveWebAssembly" />

Componente filho com um parâmetro serializável

O exemplo a seguir demonstra um componente filho interativo que recebe um parâmetro. Os parâmetros devem ser serializáveis.

RenderMode8.razor:

@page "/render-mode-8"

<SharedMessage @rendermode="InteractiveServer" Greeting="Welcome!" />

Parâmetros de componentes não serializáveis, como o conteúdo filho ou fragmento de renderização, não têm são suportados. No exemplo a seguir, passar o conteúdo filho para o componente SharedMessage resulta em um erro de runtime.

RenderMode9.razor:

@page "/render-mode-9"

<SharedMessage @rendermode="InteractiveServer">
    Child content
</SharedMessage>

Erro:

System.InvalidOperationException: não é possível passar o parâmetro 'ChildContent' para o componente 'SharedMessage' com o modo de renderização 'InteractiveServerRenderMode'. Isso ocorre porque o parâmetro é do tipo delegado 'Microsoft.AspNetCore.Components.RenderFragment', que é um código arbitrário e não pode ser serializado.

Para contornar a limitação anterior, encapsule o componente filho em outro componente que não tenha o parâmetro. Essa é a abordagem adotada no modelo de projeto de aplicativo Web Blazor com o componente Routes (Components/Routes.razor) para encapsular o componente Router.

WrapperComponent.razor:

<SharedMessage>
    Child content
</SharedMessage>

RenderMode10.razor:

@page "/render-mode-10"

<WrapperComponent @rendermode="InteractiveServer" />

No exemplo anterior:

  • O conteúdo filho é passado para o componente SharedMessage sem gerar um erro de runtime.
  • O componente SharedMessage é renderizado interativamente no servidor.

Componente filho com um modo de renderização diferente do pai

Não tente aplicar a um componente filho um modo de renderização interativo diferente do modo de renderização de seu pai.

O seguinte componente resulta em um erro de runtime quando o componente é renderizado:

RenderMode11.razor:

@page "/render-mode-11"
@rendermode InteractiveServer

<SharedMessage @rendermode="InteractiveWebAssembly" />

Erro:

Cannot create a component of type 'BlazorSample.Components.SharedMessage' because its render mode 'Microsoft.AspNetCore.Components.Web.InteractiveWebAssemblyRenderMode' is not supported by Interactive Server rendering.

Controle detalhado dos modos de renderização

Existem situações em que as especificações do aplicativo requerem que os componentes adotem a renderização estática do lado do servidor (SSR estática) e sejam executados apenas no servidor, enquanto o restante do aplicativo utiliza um modo de renderização interativo.

Existem dois métodos que podem ser adotadas para o controle detalhado dos modos de renderização, cada uma descrita nas subseções a seguir:

  • Área (pasta) de componentes de SSR estática: você possui uma área (pasta) no aplicativo com componentes que devem adotar a SSR estática e compartilhar o mesmo prefixo de caminho de rota. O aplicativo gerencia o modo de renderização de forma global, ajustando o modo de renderização no componente Routes dentro do componente App, baseando-se no caminho para a pasta.

  • Componentes de SSR estática espalhados pelo aplicativo: você tem componentes espalhados pelo aplicativo em vários locais que precisam adotar a SSR estática e serem executados apenas no servidor. Os componentes exclusivos para SSR estática não estão em uma única pasta e não compartilham um prefixo de caminho de rota comum. O aplicativo gerencia o modo de renderização individualmente para cada componente, configurando o modo de renderização com a diretiva @rendermode nas instâncias dos componentes. A reflexão é utilizada no componente App para estabelecer o modo de renderização no componente Routes.

Em ambos os casos, o componente que precisa adotar a SSR estática também deve forçar um recarregamento completo da página.

Os exemplos a seguir utilizam o parâmetro em cascata HttpContext para determinar se a página está sendo renderizada estaticamente. Um nullHttpContext indica que o componente está sendo renderizado interativamente, o que é útil como um sinal no código do aplicativo para disparar um recarregamento completo da página.

Área (pasta) de componentes de SSR estática

O método descrito nesta subseção é empregada pelo modelo de projeto Blazor Web App, que possui autenticação individual e interatividade em escala global.

Uma área (pasta) do aplicativo abriga os componentes que precisam adotar a renderização estática do lado do servidor (SSR estática) e serem executados exclusivamente no servidor. Os componentes dessa pasta compartilham o mesmo prefixo de caminho de rota. Por exemplo, os componentes IdentityRazor do modelo de projeto Blazor Web App estão localizados na pasta Components/Account/Pages e possuem o prefixo de caminho raiz /Account.

Essa pasta também inclui um arquivo _Imports.razor, que impõe um layout de conta personalizado aos componentes ali presentes:

@using BlazorSample.Components.Account.Shared
@layout AccountLayout

A pasta Shared preserva o componente de layout AccountLayout. Esse componente utiliza HttpContext para verificar se está sendo renderizado no servidor. Os componentes Identity precisam ser renderizados no servidor com SSR estática porque configuram Identitycookies. Se o valor de HttpContext for null, o componente será renderizado interativamente, e um recarregamento completo da página será realizado ao chamar NavigationManager.Refresh com forceLoad definido como true. Isso força a página a fazer uma nova renderização completa usando a SSR estática.

Components/Account/Shared/AccountLayout.razor:

@inherits LayoutComponentBase
@layout BlazorSample.Components.Layout.MainLayout
@inject NavigationManager NavigationManager

@if (HttpContext is null)
{
    <p>Loading...</p>
}
else
{
    @Body
}

@code {
    [CascadingParameter]
    private HttpContext? HttpContext { get; set; }

    protected override void OnParametersSet()
    {
        if (HttpContext is null)
        {
            NavigationManager.Refresh(forceReload: true);
        }
    }
}

Observação

No modelo de projeto Blazor Web App, há um segundo arquivo de layout (ManageLayout.razor na Components/Account/Shared pasta) para componentesIdentity na pasta Components/Account/Pages/Manage. A pasta Manage tem seu próprio arquivo _Imports.razor para ser aplicado ao ManageLayout dos componentes na pasta. Em seus próprios aplicativos, o uso de arquivos _Imports.razor aninhados é um método útil para aplicar layouts personalizados a grupos de páginas.

No componente App, qualquer pedido de um componente na pasta Account resulta na aplicação de um modo de renderização null, que impõe a SSR estática. Solicitações de outros componentes recebem o aplicativo global do modo de renderização SSR interativa (InteractiveServer).

Importante

Aplicar um modo de renderização null não garante sempre uma SSR estática. Isso só ocorre dessa forma usando o método apresentado nesta seção.

Um modo de renderização null é, na prática, equivalente a não especificar um modo de renderização, o que faz com que o componente herde o modo de renderização do seu elemento pai. Nesse caso, o componente App é renderizado com SSR estática, então um modo de renderização null faz com que o componente Routes herde a SSR estática do componente App. Se um modo de renderização nulo for especificado para um componente filho em que o elemento pai utiliza um modo de renderização interativo, o filho herda esse mesmo modo interativo.

Components/App.razor:

<Routes @rendermode="RenderModeForPage" />

...

@code {
    [CascadingParameter]
    private HttpContext HttpContext { get; set; } = default!;

    private IComponentRenderMode? RenderModeForPage => 
        HttpContext.Request.Path.StartsWithSegments("/Account")
            ? null
            : {INTERACTIVE RENDER MODE};
}

No código apresentado anteriormente, substitua o espaço reservado {INTERACTIVE RENDER MODE} pelo valor correspondente, dependendo se o restante do aplicativo deve adotar a renderização global ou InteractiveServer, InteractiveWebAssembly ou InteractiveAuto.

Os componentes que precisam adotar a SSR estática na pasta Account não precisam configurar o layout, pois é aplicado através do arquivo _Imports.razor, e esses componentes não estabelecem um modo de renderização, pois devem ser renderizados com a SSR estática. Não precisa fazer mais nada para que os componentes na pasta Account implementem a SSR estática.

Componentes de SSR estática espalhados pelo aplicativo

Como mencionado na subseção anterior, o aplicativo gerencia o modo de renderização dos componentes configurando-o de forma global no componente App. Como alternativa, o componente App também pode adotar modos de renderização específicos para cada componente, permitindo que componentes distribuídos pelo aplicativo adotem a SSR estática. Essa subseção descreve o método.

O aplicativo possui um layout personalizado que pode ser aplicado a componentes em diferentes partes do aplicativo. Geralmente, coloca-se um componente compartilhado pelo aplicativo na pasta Components/Layout. Esse componente utiliza HttpContext para verificar se está sendo renderizado no servidor. Se o valor de HttpContext for null, o componente será renderizado interativamente, e um recarregamento completo da página será realizado ao chamar NavigationManager.Refresh com forceLoad definido como true. Isso dispara uma solicitação ao servidor para o componente.

Components/Layout/StaticSsrLayout.razor:

@inherits LayoutComponentBase
@layout MainLayout
@inject NavigationManager NavigationManager

@if (HttpContext is null)
{
    <p>Loading...</p>
}
else
{
    @Body
}

@code {
    [CascadingParameter]
    private HttpContext? HttpContext { get; set; }

    protected override void OnParametersSet()
    {
        if (HttpContext is null)
        {
            NavigationManager.Refresh(forceReload: true);
        }
    }
}

No componente App, a reflexão é usada para definir o modo de renderização. Qualquer modo de renderização atribuído ao arquivo de definição de cada componente é aplicado ao componente Routes.

Components/App.razor:

<Routes @rendermode="RenderModeForPage" />

...

@code {
    [CascadingParameter]
    private HttpContext HttpContext { get; set; } = default!;

    private IComponentRenderMode? RenderModeForPage =>
        HttpContext.GetEndpoint()?.Metadata.GetMetadata<RenderModeAttribute>()?
            .Mode;
}

Cada componente que precisa adotar a SSR estática define o layout personalizado e não especifica um modo de renderização. Não especificar um modo de renderização resulta em um valor null de RenderModeAttribute.Modeno componente App, o que resulta em nenhum modo de renderização atribuído à instância do componente Routes e à implementação da SSR estática.

Importante

Aplicar um modo de renderização null não garante sempre uma SSR estática. Isso só ocorre dessa forma usando o método apresentado nesta seção.

Um modo de renderização null é, na prática, equivalente a não especificar um modo de renderização, o que faz com que o componente herde o modo de renderização do seu elemento pai. Nesse caso, o componente App é renderizado com SSR estática, então um modo de renderização null faz com que o componente Routes herde a SSR estática do componente App. Se um modo de renderização nulo for especificado para um componente filho em que o elemento pai utiliza um modo de renderização interativo, o filho herda esse mesmo modo interativo.

Nada mais deve ser feito para que os componentes imponham o SSR estático do que aplicar o layout personalizado sem definir um modo de renderização interativo:

@layout BlazorSample.Components.Layout.StaticSsrLayout

Os componentes interativos em torno do aplicativo evitam a aplicação do layout SSR estático personalizado e definem apenas um modo de renderização interativo apropriado, que após reflexão no App componente é aplicado ao Routes componente:

@rendermode {INTERACTIVE RENDER MODE}

No código apresentado anteriormente, substitua o espaço reservado {INTERACTIVE RENDER MODE} pelo valor correspondente, dependendo se o componente deve adotar a renderização InteractiveServer, InteractiveWebAssembly ou InteractiveAuto.

Os serviços do lado do cliente falham em ser resolvidos durante a pré-renderização

Supondo que a pré-renderização não esteja desabilitada para um componente ou para o aplicativo, um componente no projeto .Client é pré-renderizado no servidor. Como o servidor não tem acesso a serviços do Blazor registrados do lado do cliente, não é possível injetar esses serviços em um componente sem receber um erro de que o serviço não pode ser encontrado durante a pré-renderização.

Por exemplo, considere o seguinte componente Home no projeto .Client em um aplicativo Web Blazor com WebAssembly interativo global ou renderização automática interativa. O componente tenta injetar IWebAssemblyHostEnvironment para obter o nome do ambiente.

@page "/"
@inject IWebAssemblyHostEnvironment Environment

<PageTitle>Home</PageTitle>

<h1>Home</h1>

<p>
    Environment: @Environment.Environment
</p>

Nenhum erro de tempo de compilação ocorre, mas ocorre um erro de runtime durante a pré-renderização:

Não é possível fornecer um valor para a propriedade "Environment" no tipo "BlazorSample.Client.Pages.Home". Não há nenhum serviço registrado do tipo "Microsoft.AspNetCore.Components.WebAssembly.Hosting.IWebAssemblyHostEnvironment".

Esse erro ocorre porque o componente deve ser compilado e executado no servidor durante a pré-renderização, mas IWebAssemblyHostEnvironment não é um serviço registrado no servidor.

Se o aplicativo não exigir o valor durante a pré-renderização, esse problema poderá ser resolvido injetando IServiceProvider para obter o serviço em vez do próprio tipo de serviço:

@page "/"
@using Microsoft.AspNetCore.Components.WebAssembly.Hosting
@inject IServiceProvider Services

<PageTitle>Home</PageTitle>

<h1>Home</h1>

<p>
    <b>Environment:</b> @environmentName
</p>

@code {
    private string? environmentName;

    protected override void OnInitialized()
    {
        if (Services.GetService<IWebAssemblyHostEnvironment>() is { } env)
        {
            environmentName = env.Environment;
        }
    }
}

No entanto, a abordagem anterior não será útil se a sua lógica exigir um valor durante a pré-renderização.

Você também pode evitar o problema se desabilitar a pré-renderização do componente, mas essa é uma medida extrema e em muitos casos pode não atender às especificações do componente.

Há três abordagens que você pode adotar para resolver esse cenário. As seguintes são listadas da mais recomendada para a menos recomendada:

  • Recomendado para serviços de estrutura compartilhada: Para serviços de estrutura compartilhada que simplesmente não estão registrados no lado do servidor no projeto principal, registre os serviços no projeto principal, o que os torna disponíveis durante a pré-renderização. Para obter um exemplo desse cenário, consulte as diretrizes para serviços HttpClient em Chamar uma API Web de um aplicativo Blazor ASP.NET Core.

  • Recomendado para serviços fora da estrutura compartilhada: criar uma implementação de serviço personalizada para o serviço no servidor. Use o serviço normalmente em componentes interativos do projeto .Client. Para obter uma demonstração dessa abordagem, confira Ambientes do Blazor do AsP.NET Core.

  • Crie uma abstração de serviço e crie implementações para o serviço nos projetos do .Client e do servidor. Registre os serviços em cada projeto. Insira o serviço personalizado no componente.

  • Talvez você possa adicionar uma referência de pacote de projeto .Client a um pacote do lado do servidor e fazer fallback ao usar a API do lado do servidor durante a pré-renderização no servidor.

Descobrir componentes de assemblies adicionais

Assemblies adicionais devem ser divulgados à estrutura Blazor para descobrir componentes roteáveis Razor em projetos referenciados. Para obter mais informações, confira Roteamento e navegação do Blazor no ASP.NET Core.

Fechamento de circuitos quando não existem componentes do Servidor Interativo restantes

Os componentes do Servidor Interativo lidam com eventos da interface do usuário da Web utilizando uma conexão em tempo real com o navegador conhecida como circuito. Um circuito e seu estado associado são criados quando um componente do Servidor Interativo raiz é renderizado. O circuito é fechado quando não existem componentes do Servidor Interativo restantes na página, o que libera recursos do servidor.

Modos de renderização abreviados personalizados

A diretiva @rendermode recebe um único parâmetro que é uma instância estática do tipo IComponentRenderMode. O atributo de diretiva @rendermode pode receber qualquer instância do modo de renderização, estático ou não. A estrutura Blazor fornece a classe estática RenderMode com alguns modos de renderização predefinidos por conveniência, mas você pode criar o seu próprio.

Normalmente, um componente usa a seguinte diretiva @rendermode para desabilitar a pré-renderização:

@rendermode @(new InteractiveServerRenderMode(prerender: false))

No entanto, considere o exemplo a seguir, que cria um modo de renderização de do lado do servidor interativo com abreviação sem pré-renderizar por meio do arquivo _Imports do aplicativo (Components/_Imports.razor):

public static IComponentRenderMode InteractiveServerWithoutPrerendering { get; } = 
    new InteractiveServerRenderMode(prerender: false);

Use o modo de renderização abreviada em componentes em toda a pasta Components:

@rendermode InteractiveServerWithoutPrerendering

Como alternativa, uma única instância de componente pode definir um modo de renderização personalizado por meio de um campo privado:

@rendermode interactiveServerWithoutPrerendering

...

@code {
    private static IComponentRenderMode interactiveServerWithoutPrerendering = 
        new InteractiveServerRenderMode(prerender: false);
}

No momento, a abordagem do modo de renderização abreviado provavelmente só será útil para reduzir o detalhamento da especificação do sinalizador prerender. A abordagem abreviada poderá ser mais útil no futuro se outros sinalizadores estiverem disponíveis para renderização interativa e se você quiser criar modos de renderização abreviados com diferentes combinações de sinalizadores.

Injeção de serviço por meio de um arquivo de importação de nível superior (_Imports.razor)

Esta seção só se aplica a aplicativos Web Blazor.

Um arquivo de importação de nível superior na pasta Components (Components/_Imports.razor) injeta suas referências em todos os componentes na hierarquia de pastas, que inclui o componente App (App.razor). O componente App é sempre renderizado estaticamente, mesmo se a pré-renderização de um componente de página está desabilitada. Portanto, injetar serviços por meio do arquivo de importações de nível superior resulta na resolução de duas instâncias do serviço em componentes de página.

Para resolver esse cenário, injete o serviço em um novo arquivo de importações colocado na pasta Pages (Components/Pages/_Imports.razor). A partir desse local, o serviço só é resolvido uma vez nos componentes da página.

Recursos adicionais