Modos de representación de ASP.NET Core Blazor

En este artículo se explica el control de la representación de componentes Razor en Web Apps Blazor, ya sea en tiempo de compilación o runtime.

Esta guía no se aplica a las aplicaciones Blazor WebAssembly independientes. Las aplicaciones Blazor WebAssembly solo se representan en el cliente mediante un entorno de ejecución basado en WebAssembly del lado cliente y no tienen ningún concepto de modo de representación. Si se aplica un modo de representación a un componente de una aplicación Blazor WebAssembly, la designación del modo de representación no influye en la representación del componente.

Modos de representación

Cada componente de una aplicación web Blazor adopta un modo de representación para determinar el modelo de hospedaje que usa, dónde se representa y si es interactivo o no.

En la tabla siguiente se muestran los modos de representación disponibles para representar componentes Razor en una aplicación web Blazor. Para aplicar un modo de representación a un componente, use la directiva @rendermode en la instancia del componente o en la definición del componente. Más adelante en este artículo, se muestran ejemplos para cada escenario de modo de representación.

Nombre Descripción Ubicación de representación Interactive
Servidor estático Representación estática del lado servidor (SSR estática) Servidor No
Servidor interactivo Representación interactiva del lado servidor (SSR interactiva) mediante Blazor Server. Server
WebAssembly interactivo Representación del lado cliente (CSR) mediante Blazor WebAssembly†. Remoto
Automático interactivo SSR interactiva mediante Blazor Server inicialmente y, a continuación, CSR en las visitas posteriores después de descargar la agrupación de Blazor. Servidor y, a continuación, cliente

†Se supone que la representación del lado cliente (CSR) es interactiva. La "representación interactiva del lado cliente" y la "CSR interactiva " no se usan en el sector ni en la documentación de Blazor.

La representación previa está habilitada de forma predeterminada para componentes interactivos. Más adelante en este artículo se proporcionan instrucciones sobre el control de la representación previa. Para conocer la terminología general del sector sobre los conceptos de representación de cliente y servidor, consulte los aspectos básicos de Blazor con ASP.NET Core.

En los ejemplos siguientes se muestra cómo establecer el modo de representación del componente con algunas características básicas del componente Razor.

Para probar los comportamientos del modo de representación localmente, puede colocar los siguientes componentes en una aplicación creada a partir de la plantilla de proyecto de la aplicación web Blazor. Al crear la aplicación, seleccione las opciones en los menús desplegables (Visual Studio) o aplique las opciones de la CLI (.NET CLI) para habilitar la interactividad del lado servidor y del lado cliente. Para obtener instrucciones sobre cómo crear una aplicación web Blazor, consulte Herramientas para ASP.NET Core Blazor.

Habilitar la compatibilidad con modos de representación interactivos

Una aplicación web Blazor debe configurarse para admitir modos de representación interactivos. Las extensiones siguientes se aplican automáticamente a las aplicaciones creadas a partir de la plantilla de proyecto de aplicación web Blazor durante la creación de la aplicación. Los componentes individuales siempre deben declarar su modo de representación según la sección Modos de representación una vez que los puntos de conexión y los servicios del componente estén configurados en el archivo Program de la aplicación.

Los servicios de los componentes Razor se agregan mediante una llamada a AddRazorComponents.

Extensiones del generador de componentes:

MapRazorComponents detecta los componentes disponibles y especifica el componente raíz de la aplicación (el primer componente cargado), que de forma predeterminada es el componente App (App.razor).

Extensiones del generador de convención de punto de conexión:

Nota:

Para obtener orientación sobre la ubicación de la API en los ejemplos siguientes, inspeccione el archivo Program de una aplicación generada a partir de la plantilla de proyecto aplicación web Blazor. Para obtener instrucciones sobre cómo crear una aplicación web Blazor, consulte Herramientas para ASP.NET Core Blazor.

Ejemplo 1: la siguiente API de archivo Program agrega servicios y configuración para habilitar la SSR interactiva:

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

Ejemplo 2: la siguiente API de archivo Program agrega servicios y configuración para habilitar el modo de representación WebAssembly interactivo:

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

Ejemplo 3: la siguiente API de archivo Program agrega servicios y configuración para habilitar los modos de representación Servidor interactivo, WebAssembly interactivo y Automático interactivo:

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

Blazor usa el modelo de hospedaje Blazor WebAssembly para descargar y ejecutar componentes que usan el modo de representación WebAssembly interactivo. Se requiere un proyecto de cliente independiente para configurar el hospedaje Blazor WebAssembly para estos componentes. El proyecto de cliente contiene el código de inicio del host Blazor WebAssembly y configura el entorno de ejecución de .NET para ejecutarse en un explorador. La plantilla de aplicación web Blazor agrega este proyecto de cliente automáticamente al seleccionar la opción para habilitar la interactividad de WebAssembly. Los componentes que usen el modo de representación WebAssembly interactivo deben compilarse a partir del proyecto de cliente, por lo que se incluyen en el lote de aplicaciones descargado.

Aplicar un modo de representación a una instancia de componente

Para aplicar un modo de representación a una instancia de componente, use el atributo de directiva @rendermodeRazor donde se usa el componente.

En el ejemplo siguiente, la representación interactiva del lado servidor (SSR interactiva) se aplica a la instancia del componente Dialog:

<Dialog @rendermode="InteractiveServer" />

Nota:

Las plantillas Blazor incluyen una directiva estática using para RenderMode en el archivo de _Imports la aplicación (Components/_Imports.razor) para una sintaxis más corta @rendermode:

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

Sin la directiva anterior, los componentes deben especificar la clase estática RenderMode en la sintaxis @rendermode:

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

También puede hacer referencia a instancias del modo de representación personalizado creadas directamente con la configuración personalizada. Para obtener más información, vea la sección Modos de representación abreviados personalizados más adelante en este artículo.

Aplicar un modo de representación a una definición de componente

Para especificar el modo de representación de un componente como parte de su definición, use la directiva @rendermodeRazor y el atributo de modo de representación correspondiente.

@page "..."
@rendermode InteractiveServer

La aplicación de un modo de representación a una definición de componente se usa normalmente al aplicar un modo de representación a una página específica. Las páginas enrutables de forma predeterminada usan el mismo modo de representación que el componente Router que ha representado la página.

Técnicamente, @rendermode es una Razordirectiva y un Razoratributo de directiva. La semántica es similar, pero hay diferencias. La directiva @rendermode está en la definición del componente, por lo que la instancia del modo de representación a la que se hace referencia debe ser estática. El atributo de directiva @rendermode puede tomar cualquier instancia del modo de representación.

Nota:

Los autores de componentes deben evitar acoplar la implementación de un componente a un modo de representación específico. En su lugar, los autores de componentes normalmente deben diseñar componentes para admitir cualquier modo de representación o modelo de hospedaje. La implementación de un componente debe evitar suposiciones sobre dónde se ejecuta (servidor o cliente) y debe degradarse correctamente cuando se representa estáticamente. Es posible que sea necesario especificar el modo de representación en la definición del componente si no se crea una instancia del componente directamente (por ejemplo, con un componente de página enrutable) o para especificar un modo de representación para todas las instancias del componente.

Aplicación de un modo de representación en toda la aplicación

Para establecer el modo de representación para toda la aplicación, indique el modo de representación en el componente interactivo de nivel más alto de la jerarquía de componentes de la aplicación que no es un componente raíz.

Nota:

No se admite la creación de un componente raíz interactivo, como el componente App. Por tanto, el componente App no puede establecer directamente el modo de representación para toda la aplicación.

En el caso de las aplicaciones basadas en la plantilla de proyecto de aplicación web Blazor, un modo de representación asignado a toda la aplicación suele especificarse donde se usa el componente Routes en el componente App (Components/App.razor):

<Routes @rendermode="InteractiveServer" />

El componente Router propaga su modo de representación a las páginas que enruta.

Normalmente, también debe establecer el mismo modo de representación interactivo en el componente HeadOutlet, que también se encuentra en el componente App de una aplicación web Blazor generada a partir de la plantilla del proyecto:

<HeadOutlet @rendermode="InteractiveServer" />

En el caso de las aplicaciones que adoptan un modo de representación interactivo del lado cliente (WebAssembly o Automático) y habilitan el modo de representación para toda la aplicación a través del componenteRoutes:

  • Coloque o mueva los archivos de diseño y navegación de la carpeta Components/Layout de la aplicación del servidor a la carpeta Layout del proyecto .Client. Cree una carpeta Layout en el proyecto .Client si todavía no existe.
  • Coloque o mueva los componentes de la carpeta Components/Pages de la aplicación del servidor a la carpeta Pages del proyecto .Client. Cree una carpeta Pages en el proyecto .Client si todavía no existe.
  • Coloque o mueva el componente Routes de la carpeta Components de la aplicación del servidor a la carpeta raíz del proyecto .Client.

Para habilitar la interactividad global al crear una aplicación web Blazor:

  • Visual Studio: establezca la lista desplegable Ubicación de interactividad en Global.
  • CLI de .NET: usar la opción -ai|--all-interactive.

Para más información, vea Herramientas para ASP.NET Core Blazor.

Aplicar un modo de representación mediante programación

Las propiedades y los campos pueden asignar modos de representación.

El segundo enfoque descrito en esta sección, establecer el modo de representación por instancia de componente, resulta especialmente útil cuando la especificación de la aplicación llama a cualquiera de los escenarios siguientes:

  • Tiene un área (carpeta) de la aplicación con componentes que deben adoptar la representación estática del lado servidor (SSR estática) y que solo se ejecutan en el servidor. La aplicación controla el modo de representación globalmente estableciendo el modo de representación del componente Routes en el componente App en función de la ruta de acceso a la carpeta.
  • Tiene componentes en torno a la aplicación en varias ubicaciones (no en una sola carpeta) que deben adoptar la SSR estática y que solo se ejecutan en el servidor. La aplicación controla el modo de representación por componente estableciendo el modo de representación con la directiva @rendermode en instancias de componentes. Se usa la reflexión del componente App para establecer el modo de representación en el componente Routes.

En ambos casos, el componente que deba adoptar la SSR estática también deberá forzar una recarga de página completa.

Los dos escenarios anteriores se tratan con ejemplos en la sección Control detallado de los modos de representación que veremos más adelante en este artículo. Las dos subsecciones siguientes se centran en los enfoques básicos de configuración del modo de representación.

Establecimiento del modo de representación por definición de componente

Una definición de componente puede definir un modo de representación a través de un campo privado:

@rendermode renderModeForPage

...

@code {
    private static IComponentRenderMode renderModeForPage = InteractiveServer;
}

Establecimiento del modo de representación por instancia de componente

En el ejemplo siguiente, se aplica la representación interactiva del lado servidor (SSR interactiva) a cualquier solicitud.

<Routes @rendermode="RenderModeForPage" />

...

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

Se proporciona información adicional sobre la propagación del modo de representación en la sección Propagación del modo de representación más adelante en este artículo. La sección Control detallado de los modos de representación muestra cómo usar el enfoque anterior para adoptar la SSR estática en áreas específicas de la aplicación (carpetas) o para componentes específicos distribuidos alrededor de la aplicación con asignaciones de modo de representación por componente.

Representación previa

La representación previa es el proceso de representación inicial del contenido de la página en el servidor sin habilitar controladores de eventos para controles representados. El servidor genera la interfaz de usuario HTML de la página lo antes posible en respuesta a la solicitud inicial, lo que hace que la aplicación se sienta más sensible a los usuarios. La representación previa también puede mejorar la optimización del motor de búsqueda (SEO) mediante la representación del contenido de la respuesta HTTP inicial que los motores de búsqueda usan para calcular la clasificación de página.

La representación previa está habilitada de forma predeterminada para componentes interactivos.

Para deshabilitar la representación previa de una instancia de componente, pase la marca prerender con un valor de false para representar el modo:

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

Para deshabilitar la representación previa en una definición de componente:

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

Para deshabilitar la representación previa para toda la aplicación, indique el modo de representación en el componente interactivo de nivel más alto de la jerarquía de componentes de la aplicación que no es un componente raíz.

En el caso de las aplicaciones basadas en la plantilla de proyecto de aplicación web Blazor, un modo de representación asignado a toda la aplicación se especifica donde se usa el componente Routes en el componente App (Components/App.razor). En el ejemplo siguiente se establece el modo de representación de la aplicación en Servidor interactivo con la representación previa deshabilitada:

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

Además, deshabilite la representación previa para el HeadOutletcomponente en el componente App:

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

No se admite la creación de un componente raíz, como el componente App, interactivo con la directiva @rendermode en la parte superior del archivo de definición del componente raíz (.razor). Por lo tanto, el componente App no puede deshabilitar la representación previa directamente.

Representación estática del lado servidor (SSR estática)

De forma predeterminada, los componentes usan la representación estática del lado servidor (SSR estática). El componente se representa en el flujo de respuesta y la interactividad no está habilitado.

En el ejemplo siguiente, no hay ninguna designación para el modo de representación del componente, de forma que el componente hereda su modo de representación del elemento primario. Como ningún componente antecesor especifica un modo de representación, el siguiente componente se representa estáticamente en el servidor. El botón no es interactivo y no llama al método UpdateMessage cuando se selecciona. El valor de message no cambia y el componente no se vuelve a representar en respuesta a los eventos de la interfaz de usuario.

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!";
    }
}

Si usa el componente anterior localmente en una aplicación web Blazor, coloque el componente en la carpeta Components/Pages del proyecto de servidor. El proyecto de servidor es el proyecto de la solución con un nombre que no termina en .Client. Cuando se ejecute la aplicación, vaya a /render-mode-1 en la barra de direcciones del explorador.

Durante la SSR estática, las solicitudes de página de componentes Razor se procesan en el procesamiento de solicitudes de canalización de middleware de ASP.NET Core del lado servidor para el enrutamiento y la autorización. Las características de Blazor dedicadas para el enrutamiento y la autorización no están operativas porque los componentes Razor no se representan durante el procesamiento de solicitudes del lado servidor. Las características del enrutador de Blazor en el componente Routes que no están disponibles durante la SSR estática incluyen la visualización de:

Si la aplicación muestra interactividad a nivel raíz, el procesamiento de solicitudes de ASP.NET Core del lado servidor no está implicado después de la SSR estática inicial, lo que significa que las características de Blazor anteriores funcionan según lo previsto.

La navegación mejorada con SSR estática requiere especial atención al cargar JavaScript. Para obtener más información, consulte ASP.NET Core Blazor JavaScript con representación estática del lado servidor.

Representación interactiva del lado servidor (SSR interactiva)

La representación interactiva del lado servidor (SSR interactiva) representa el componente de forma interactiva desde el servidor mediante Blazor Server. Las interacciones del usuario se controlan a través de una conexión en tiempo real con el explorador. La conexión del circuito se establece cuando se representa el componente Servidor.

En el ejemplo siguiente, el modo de representación se establece en SSR interactiva agregando @rendermode InteractiveServer a la definición del componente. El botón llama al método UpdateMessage cuando se selecciona. El valor de message cambia y el componente se vuelve a representar para actualizar el mensaje en la interfaz de usuario.

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!";
    }
}

Si usa el componente anterior localmente en una aplicación web Blazor, coloque el componente en la carpeta Components/Pages del proyecto de servidor. El proyecto de servidor es el proyecto de la solución con un nombre que no termina en .Client. Cuando se ejecute la aplicación, vaya a /render-mode-2 en la barra de direcciones del explorador.

Representación del lado cliente (CSR)

La representación del lado cliente (CSR) representa el componente de forma interactiva en el cliente mediante Blazor WebAssembly. El entorno de ejecución de .NET y el lote de aplicaciones se descargan y almacenan en caché cuando el componente WebAssembly se representa inicialmente. Los componentes que usan la CSR deben compilarse a partir de un proyecto de cliente independiente que configure el host Blazor WebAssembly.

En el ejemplo siguiente, el modo de representación se configura en CSR con @rendermode InteractiveWebAssembly. El botón llama al método UpdateMessage cuando se selecciona. El valor de message cambia y el componente se vuelve a representar para actualizar el mensaje en la interfaz de usuario.

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!";
    }
}

Si usa el componente anterior localmente en una aplicación web Blazor, coloque el componente en la carpeta Pages del proyecto de cliente. El proyecto de cliente es el proyecto de la solución con un nombre que termina en .Client. Cuando se ejecute la aplicación, vaya a /render-mode-3 en la barra de direcciones del explorador.

Representación automática (Automático)

El modo de representación automática (Automático) determina cómo representar el componente en el runtime. El componente se representa inicialmente con la representación interactiva del lado servidor (SSR interactiva) mediante el modelo de hospedaje Blazor Server. El runtime de .NET y el lote de aplicaciones se descargan en el cliente en segundo plano y se almacenan en caché para que se puedan usar en futuras visitas.

El modo de representación Automático nunca cambia dinámicamente el modo de representación de un componente que ya está en la página. El modo de representación Automático toma una decisión inicial sobre el tipo de interactividad que se va a usar para un componente y, después, el componente mantiene ese tipo de interactividad mientras esté en la página. Un factor de esta decisión inicial es considerar si los componentes ya existen en la página con interactividad de WebAssembly/Server. El modo Automático prefiere seleccionar un modo de representación que coincida con el de los componentes interactivos existentes. La razón por la que el modo Automático prefiere usar un modo de interactividad existente es evitar la introducción de un nuevo runtime interactivo que no comparte el estado con el runtime existente.

Los componentes que usan el modo de representación Automático deben compilarse a partir de un proyecto de cliente independiente que configure el host Blazor WebAssembly.

En el ejemplo siguiente, el componente es interactivo en todo el proceso. El botón llama al método UpdateMessage cuando se selecciona. El valor de message cambia y el componente se vuelve a representar para actualizar el mensaje en la interfaz de usuario. Inicialmente, el componente se representa de forma interactiva desde el servidor, pero en las visitas posteriores se representa desde el cliente después de descargar y almacenar en caché el lote de aplicaciones y el runtime de .NET.

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!";
    }
}

Si usa el componente anterior localmente en una aplicación web Blazor, coloque el componente en la carpeta Pages del proyecto de cliente. El proyecto de cliente es el proyecto de la solución con un nombre que termina en .Client. Cuando se ejecute la aplicación, vaya a /render-mode-4 en la barra de direcciones del explorador.

Propagación del modo de representación

Los modos de representación propagan la jerarquía de componentes.

Reglas para aplicar modos de representación:

  • El modo de representación predeterminado es Estático.
  • Los modos de representación Servidor interactivo (InteractiveServer), WebAssembly interactivo (InteractiveWebAssembly) y Automático interactivo (InteractiveAuto) se pueden usar desde un componente, incluido el uso de diferentes modos de representación para los componentes del mismo nivel.
  • No se puede cambiar a otro modo de representación interactivo en un componente secundario. Por ejemplo, un componente Servidor no puede ser un elemento secundario de un componente WebAssembly.
  • Los parámetros pasados a un componente secundario interactivo a partir de un elemento primario estático deben ser serializables JSON. Esto significa que no se pueden pasar fragmentos de representación o contenido secundario de un componente primario estático a un componente secundario interactivo.

En los ejemplos siguientes se usa un componente SharedMessage que no es enrutable ni una página. El componente SharedMessage independiente del modo de representación no aplica un modo de representación con una directiva @attribute. Si va a probar estos escenarios con una aplicación web Blazor, coloque el siguiente componente en la carpeta Components de la aplicación.

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!";
    }
}

Herencia del modo de representación

Si el componente SharedMessage se coloca en un componente primario representado estáticamente, el componente SharedMessage también se representa estáticamente y no es interactivo. El botón no llama a UpdateMessage y el mensaje no se actualiza.

RenderMode5.razor:

@page "/render-mode-5"

<SharedMessage />

Si el componente SharedMessage se coloca en un componente que define el modo de representación, hereda el modo de representación aplicado.

En el ejemplo siguiente, el componente SharedMessage es interactivo a través de una conexión SignalR al cliente. El botón llama a UpdateMessage y el mensaje se actualiza.

RenderMode6.razor:

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

<SharedMessage />

Componentes secundarios con diferentes modos de representación

En el ejemplo siguiente, ambos componentes SharedMessage se presentan previamente (de forma predeterminada) y aparecen cuando la página se muestra en el explorador.

  • El primer componente SharedMessage con la representación interactiva del lado servidor (SSR interactiva) es interactivo después de establecer el circuito SignalR.
  • El segundo componente SharedMessage con la representación del lado cliente (CSR) es interactivo después de que el lote de aplicaciones Blazor se haya descargado y el runtime de .NET esté activo en el cliente.

RenderMode7.razor:

@page "/render-mode-7"

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

Componente secundario con un parámetro serializable

En el ejemplo siguiente se muestra un componente secundario interactivo que toma un parámetro. Los parámetros deben ser serializables.

RenderMode8.razor:

@page "/render-mode-8"

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

No se admiten los parámetros de componentes no serializables, como el contenido secundario o un fragmento de representación. En el ejemplo siguiente, pasar contenido secundario al componente SharedMessage produce un error de runtime.

RenderMode9.razor:

@page "/render-mode-9"

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

Error:

System.InvalidOperationException: no se puede pasar el parámetro "ChildContent" al componente "SharedMessage" con el modo de representación "InteractiveServerRenderMode". Esto se debe a que el parámetro es del tipo delegado "Microsoft.AspNetCore.Components.RenderFragment", que es código arbitrario y no se puede serializar.

Para eludir la limitación anterior, encapsule el componente secundario en otro componente que no tenga el parámetro. Este es el enfoque adoptado en la plantilla de proyecto de la aplicación web Blazor con el componente Routes (Components/Routes.razor) para encapsular el componenteRouter.

WrapperComponent.razor:

<SharedMessage>
    Child content
</SharedMessage>

RenderMode10.razor:

@page "/render-mode-10"

<WrapperComponent @rendermode="InteractiveServer" />

En el ejemplo anterior:

  • El contenido secundario se pasa al componente SharedMessage sin generar un error de runtime.
  • El componente SharedMessage se representa de forma interactiva en el servidor.

Componente secundario con un modo de representación diferente al primario

No intente aplicar a un componente secundario un modo de representación interactivo distinto del modo de representación de su elemento primario.

El siguiente componente produce un error de runtime cuando se representa el componente:

RenderMode11.razor:

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

<SharedMessage @rendermode="InteractiveWebAssembly" />

Error:

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.

Control detallado de los modos de representación

Hay casos en los que la especificación de la aplicación llamará a los componentes para adoptar la representación estática del lado servidor (SSR estática) y solo se ejecutará en el servidor, mientras que el resto de la aplicación usará un modo de representación interactiva.

Hay dos enfoques que se pueden adoptar para controlar detalladamente los modos de representación, cada uno de los cuales se describe en las siguientes subsecciones:

  • Área (carpeta) de componentes de SSR estática: tiene un área (carpeta) de la aplicación con componentes que deben adoptar la SSR estática y compartir el mismo prefijo de ruta de acceso. La aplicación controla el modo de representación globalmente estableciendo el modo de representación del componente Routes en el componente App en función de la ruta de acceso a la carpeta.

  • Componentes de SSR estática distribuidos por la aplicación: tiene componentes repartidos por la aplicación en varias ubicaciones que deben adoptar la SSR estática y que solo se ejecutan en el servidor. Los componentes que solo son de SSR estática no están en una sola carpeta y no comparten un prefijo de ruta de acceso común. La aplicación controla el modo de representación por componente estableciendo el modo de representación con la directiva @rendermode en instancias de componentes. Se usa la reflexión del componente App para establecer el modo de representación en el componente Routes.

En ambos casos, el componente que deba adoptar la SSR estática también deberá forzar una recarga de página completa.

En los ejemplos siguientes, se usa el parámetro en cascada HttpContext para determinar si la página se representa estáticamente. Un nullHttpContext indica que el componente se representa de forma interactiva, lo que resulta útil como señal en el código de la aplicación para desencadenar una recarga de página completa.

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

La plantilla de proyecto de aplicación web Blazor usa el enfoque descrito en esta subsección con autenticación individual e interactividad global.

Un área (carpeta) de la aplicación contiene los componentes que debe adoptar la SSR estática y que solo se ejecutan en el servidor. Los componentes de la carpeta comparten el mismo prefijo de ruta de acceso. Por ejemplo, los componentes IdentityRazor de la plantilla de proyecto de aplicación web Blazor están en la carpeta Components/Account/Pages y comparten el prefijo de ruta de acceso raíz /Account.

La carpeta también contiene un archivo _Imports.razor, que aplica un diseño de cuenta personalizado a los componentes de la carpeta:

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

La carpeta Shared mantiene el componente de diseño AccountLayout. El componente usa HttpContext para determinar si el componente se representa en el servidor. Los componentes Identity deben representarse en el servidor con la SSR estática porque establecen Identitycookie. Si el valor de HttpContext es null, el componente se representa de forma interactiva y se realiza una recarga de página completa llamando a NavigationManager.Refresh con forceLoad establecido en true. Esto fuerza una representación completa de la página mediante la 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);
        }
    }
}

Nota:

En la plantilla de proyecto de aplicación web Blazor, hay un segundo archivo de diseño (ManageLayout.razor en la carpeta Components/Account/Shared) para los componentes Identity de la carpeta Components/Account/Pages/Manage. La carpeta Manage tiene su propio archivo _Imports.razor para aplicar al ManageLayout para los componentes de la carpeta. En sus propias aplicaciones, el uso de archivos _Imports.razor anidados es un enfoque útil para aplicar diseños personalizados a grupos de páginas.

En el componente App, cualquier solicitud de un componente de la carpeta Account aplica un modo de representación null que aplica la SSR estática. Otras solicitudes de componentes reciben una aplicación global del modo de representación de SSR interactiva (InteractiveServer).

Importante

La aplicación de un modo de representación null no siempre aplica la SSR estática. Simplemente, ocurre que se comporta de esa manera con el enfoque que se muestra en esta sección.

Un modo de representación null resulta prácticamente lo mismo que no especificar un modo de representación, lo que da como resultado que el componente herede el modo de representación de su elemento primario. En este caso, el componente App se representará mediante la SSR estática, por lo que un modo de representación null dará como resultado el componente Routes heredando la SSR estática del componente App. Si se especificase un modo de representación null para un componente secundario cuyo elemento primario usase un modo de representación interactiva, el elemento secundario heredará el mismo modo de representación interactiva.

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};
}

En el código anterior, cambie el marcador de posición {INTERACTIVE RENDER MODE} por el valor adecuado, en función de si el resto de la aplicación debiera adoptar la representación global InteractiveServer, InteractiveWebAssembly o InteractiveAuto.

Los componentes que deberán adoptar la SSR estática en la carpeta Account no son necesarios para establecer el diseño porque se aplica a través del archivo _Imports.razor, y los componentes no establecerán un modo de representación porque deben representarse con la SSR estática. No se debe hacer nada más para que los componentes de la carpeta Account apliquen la SSR estática.

Componentes de SSR estática distribuidos por la aplicación

En la subsección anterior, la aplicación controla el modo de representación de los componentes estableciendo el modo de representación globalmente en el componente App. Como alternativa, el componente App también puede adoptar modos de representación por componente para establecer el modo de representación, lo que permite que los componentes se extiendan por la aplicación para aplicar la adopción de la SSR estática. En esta subsección se describe el enfoque.

La aplicación tiene un diseño personalizado que se puede aplicar a los componentes de la aplicación. Normalmente, un componente compartido para la aplicación se coloca en la carpeta Components/Layout. El componente usa HttpContext para determinar si el componente se representa en el servidor. Si el valor de HttpContext es null, el componente se representa de forma interactiva y se realiza una recarga de página completa llamando a NavigationManager.Refresh con forceLoad establecido en true. Esto desencadena una solicitud al servidor para el 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);
        }
    }
}

En el componente App, la reflexión se usa para establecer el modo de representación. El modo de representación que se asigne al archivo de definición del componente individual se aplicará al 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 deba adoptar la SSR estática establecerá el diseño personalizado y no especificará un modo de representación. Si no se especificase un modo de representación, se obtendrá un valor de null de RenderModeAttribute.Mode en el componente App, lo que no dará como resultado ningún modo de representación asignado a la instancia de componente Routes y a la aplicación de la SSR estática.

Importante

La aplicación de un modo de representación null no siempre aplica la SSR estática. Simplemente, ocurre que se comporta de esa manera con el enfoque que se muestra en esta sección.

Un modo de representación null resulta prácticamente lo mismo que no especificar un modo de representación, lo que da como resultado que el componente herede el modo de representación de su elemento primario. En este caso, el componente App se representará mediante la SSR estática, por lo que un modo de representación null dará como resultado el componente Routes heredando la SSR estática del componente App. Si se especificase un modo de representación null para un componente secundario cuyo elemento primario usase un modo de representación interactiva, el elemento secundario heredará el mismo modo de representación interactiva.

No se debe hacer nada más para que los componentes apliquen la SSR estática que aplicar el diseño personalizado sin establecer un modo de representación interactiva:

@layout BlazorSample.Components.Layout.StaticSsrLayout

Los componentes interactivos de la aplicación evitan aplicar el diseño personalizado de SSR estática y solo establecen un modo de representación interactiva adecuado, que tras la reflexión del componente App se aplica al componente Routes:

@rendermode {INTERACTIVE RENDER MODE}

En el código anterior, cambie el marcador de posición {INTERACTIVE RENDER MODE} por el valor adecuado, en función de si el componente debiera adoptar la representación InteractiveServer, InteractiveWebAssembly o InteractiveAuto.

Los servicios del lado cliente no se resuelven durante la representación previa

Suponiendo que la representación previa no está deshabilitada para un componente o para la aplicación, un componente del proyecto .Client se representa previamente en el servidor. Dado que el servidor no tiene acceso a los servicios Blazor registrados del lado cliente, no es posible insertar estos servicios en un componente sin recibir un error que indica que el servicio no se puede encontrar durante la representación previa.

Por ejemplo, considere el siguiente componente Home en el proyecto .Client de una aplicación web Blazor con la representación automática interactiva o la representación interactiva de WebAssembly global. El componente intenta insertar IWebAssemblyHostEnvironment para obtener el nombre del entorno.

@page "/"
@inject IWebAssemblyHostEnvironment Environment

<PageTitle>Home</PageTitle>

<h1>Home</h1>

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

No se produce ningún error en tiempo de compilación, pero se produce un error en tiempo de ejecución durante la representación previa:

No se puede proporcionar un valor para la propiedad "Environment" en el tipo "BlazorSample.Client.Pages.Home". No hay ningún servicio registrado de tipo "Microsoft.AspNetCore.Components.WebAssembly.Hosting.IWebAssemblyHostEnvironment".

Este error se produce porque el componente debe compilarse y ejecutarse en el servidor durante la representación previa, pero IWebAssemblyHostEnvironment no es un servicio registrado en el servidor.

Si la aplicación no requiere el valor durante la representación previa, este problema se puede resolver insertando IServiceProvider para obtener el servicio en lugar del propio tipo de servicio:

@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;
        }
    }
}

Sin embargo, el enfoque anterior no es útil si la lógica requiere un valor durante la representación previa.

También puede evitar el problema si deshabilita la representación previa del componente, pero es una medida extrema que se debe tomar en muchos casos que no cumplan las especificaciones del componente.

Hay tres enfoques que puede adoptar para abordar este escenario. Se presentan a continuación, del más al menos recomendado:

  • Recomendado para servicios de marco compartidos: para los servicios de marco compartidos que simplemente no están registrados en el lado del servidor en el proyecto principal, registre los servicios en el proyecto principal, lo que hace que estén disponibles durante la representación previa. Para obtener un ejemplo de este escenario, consulte las instrucciones para los servicios de HttpClient en Llamada a una API web desde una aplicación de ASP.NET Core Blazor.

  • Recomendado para servicios fuera del marco compartido: cree una implementación de servicio personalizada para el servicio en el servidor. Normalmente, use el servicio en componentes interactivos del proyecto .Client. Para obtener una demostración de este enfoque, consulte los entornosBlazor de ASP.NET Core.

  • Cree una abstracción de servicio y cree implementaciones para el servicio en los proyectos de servidor y .Client. Registre los servicios en cada proyecto. Inserte el servicio personalizado en el componente.

  • Es posible que pueda agregar una referencia de paquete de proyecto .Client a un paquete del lado servidor y revertir al uso de la API del lado servidor al realizar la representación previa en el servidor.

Detección de componentes de ensamblados adicionales

Los ensamblados adicionales deben revelarse al marco de Blazor para detectar componentes de Razor enrutables en proyectos a los que se hace referencia. Para más información, vea Enrutamiento y navegación de Blazor de ASP.NET Core.

Cierre de circuitos cuando no haya componentes del servidor interactivo restantes

Los componentes del Servidor interactivo controlan los eventos de la interfaz de usuario web mediante una conexión en tiempo real con el explorador denominado circuito. Un circuito y su estado asociado se crean cuando se representa un componente de Servidor interactivo raíz. El circuito se cierra cuando no quedan componentes de Servidor interactivo en la página, lo que libera los recursos del servidor.

Modos de representación abreviados personalizados

La directiva @rendermode toma un único parámetro que es una instancia estática de tipo IComponentRenderMode. El atributo de directiva @rendermode puede tomar cualquier instancia del modo de representación, estática o no. El marco de Blazor proporciona la clase estática RenderMode con algunos modos de representación predefinidos para mayor comodidad, pero puede crear los suyos propios.

Normalmente, un componente usa la siguiente directiva @rendermode para deshabilitar la representación previa:

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

Sin embargo, considere el ejemplo siguiente que crea un modo de representación interactivo del lado servidor abreviado sin representación previa mediante el archivo _Imports de la aplicación (Components/_Imports.razor):

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

Use el modo de representación abreviado en componentes en toda la carpeta Components:

@rendermode InteractiveServerWithoutPrerendering

Como alternativa, una única instancia de componente puede definir un modo de representación personalizado mediante un campo privado:

@rendermode interactiveServerWithoutPrerendering

...

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

Por el momento, el enfoque del modo de representación abreviado probablemente solo sea útil para reducir el nivel de detalle de especificar la marca prerender. El enfoque abreviado podría ser más útil en el futuro si se dispone de marcas adicionales para la representación interactiva y se desea crear modos de representación abreviados con diferentes combinaciones de marcas.

Inserción de servicios a través de un archivo de importación de nivel superior (_Imports.razor)

Esta sección solo se aplica a Web Apps Blazor.

Un archivo de importación de nivel superior en la carpeta Components (Components/_Imports.razor) inserta sus referencias en todos los componentes de la jerarquía de carpetas, que incluye el componente App (App.razor). El componente App siempre se representa estáticamente incluso si la representación previa de un componente de página está deshabilitado. Por lo tanto, la inserción de servicios a través del archivo de importación de nivel superior da como resultado la resolución de dos instancias del servicio en los componentes de página.

Para solucionar este escenario, inserte el servicio en un nuevo archivo de importaciones colocado en la carpeta Pages (Components/Pages/_Imports.razor). Desde esa ubicación, el servicio solo se resuelve una vez en los componentes de la página.

Recursos adicionales