Saltar al contenido

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript... y lo que venga ;)

17 años online

el blog de José M. Aguilar

Inicio El autor Contactar

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web
ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript...

¡Microsoft MVP!
martes, 27 de octubre de 2020
Blazor

Hace unos días, un alumno de mi curso de Blazor en CampusMVP me preguntaba sobre la posibilidad de detectar cuándo un componente se estaba procesando en "modo prerenderización", con el fin de ejecutar cierta lógica únicamente en ese caso.

Me habría gustado responderle algo como "usa la propiedad IsPrerendering del componente y ya lo tienes". Pero no, las cosas no son tan sencillas; Blazor no proporciona ninguna propiedad del estilo, y no existen fórmulas directas para conseguirlas, más allá de un par de hacks bastante poco elegantes:

  • Intentar acceder al contexto HTTP, sólo disponible cuando estamos ejecutando código en el interior de una petición (es decir, cuando el componente se está prerenderizando).
  • Ejecutar una función Javascript mediante interop, y capturar la excepción que se produce al hacerlo mientras se está prerenderizando el resultado, pues durante este proceso no es posible utilizar los mecanismos de interoperación.

En este post vamos a ver una alternativa más apropiada que las anteriores, sacando partido al inyector de dependencias y al hecho de que la prerenderización se ejecuta en el propio proceso de la petición que carga la página inicialmente. Y como veréis, la idea es muy sencilla.

¡Manos a la obra!

En primer lugar, vamos a crear un servicio para almacenar el modo de renderización actual. Basta con algo tan simple como lo siguiente:

public class RenderStatus
{
    public bool IsPrerendering { get; set; }
}

A continuación, registramos el servicio como scoped en el inyector de dependencias de ASP.NET Core, en Startup.cs, de forma que las instancias de RenderStatus sean distintas para cada petición entrante:

public void ConfigureServices(IServiceCollection services)
{
    ... // Otros servicios
    services.AddScoped<RenderStatus>();
}

Fijaos que a partir de ese momento, ya podríamos inyectar la dependencia RenderStatus en cualquier componente, aunque su propiedad IsPrerendering de momento siempre valdrá false, el valor por defecto.

Dado que nos interesa que IsPrerendering sea cierto durante la prerenderización, lo más sencillo es acudir a la página contenedora de la aplicación Pages/_Host.cshtml y establecerlo manualmente justo en el momento en que el componente Blazor va ser prerenderizado:

@page "/"
@inject RenderStatus RenderStatus
...
<body>
    @{
        RenderStatus.IsPrerendering = true;
    }
    <component type="typeof(App)" render-mode="ServerPrerendered" />
    @{
        RenderStatus.IsPrerendering = false;
    }
    ...

¡Eso es todo! A partir de este momento ya podríamos inyectar el servicio RenderStatus en cualquier componente Blazor y usar su propiedad IsPrerendering para saber si está siendo prerenderizado o no, y actuar en consecuencia.

Por ejemplo, el siguiente componente utiliza el servicio para evitar que durante la prerenderización se realice una tarea compleja que podría hacer que la carga de la primera página se retrasase:

@page "/test"
@inject RenderStatus RenderStatus

<h1>@message</h1>

@code {
    string message = "Starting...";
    protected override async Task OnInitializedAsync()
    {
        if (!RenderStatus.IsPrerendering)
        {
            message = "Calculating...";
            await Task.Delay(2000); // Do something complex here...
            message = "Done!";
        }
    }
}

¡Espero que os sea de ayuda!

Publicado en Variable not found.

Aún no hay comentarios, ¡sé el primero!