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

18 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, 21 de marzo de 2017
ASP.NET Core MVCSabemos que mientras se renderiza una vista Razor, por defecto el framework MVC va almacenando el resultado en memoria, y sólo al finalizar es cuando comienza a retornarlo al lado cliente.

Por ejemplo, en la ejecución del siguiente código Razor, el usuario que solicitó la página no vería absolutamente nada durante 10 segundos, y de pronto le llegaría el resultado completo:
@using System.Threading.Tasks
@{
    Layout = null;
}
<html>
<head>
    <title>Hello world!</title>
</head>
<body>
    <h1>Let's go</>
    <ul>
        @for (int i = 0; i < 10; i++)
        {
            await Task.Delay(1000);
            <li>@i</li>
        }
    </ul>
</body>
</html>
Nota: Observad que para hacer el retardo, en lugar del típico Thread.Sleep() he utilizado Task.Delay() sólo para recordaros que en ASP.NET Core las vistas se renderizan/ejecutan en un contexto asíncrono y, por tanto, podemos utilizar en su interior llamadas con await como hacemos en otros puntos del código.


Aunque en muchos escenarios el comportamiento por defecto de buffering de la salida es válido, hay veces en las que nos interesaría ir enviando al lado cliente las porciones de página que ya han sido generadas. Esto puede reducir el consumo de memoria en el servidor, disminuir el tiempo de espera hasta el primer byte percibido desde el cliente y, como consecuencia, mejorar el rendimiento de nuestra aplicación web.

ASP.NET Core ofrece la posibilidad de "flushear" el contenido en los momentos que nos interese mediante el método FlushAsync() disponible en la clase RazorPage de la que heredan normalmente nuestras vistas. En el momento en que lo invoquemos, todo el contenido renderizado hasta el momento será enviado al cliente a través del canal de salida y eliminado del buffer.

Así, si en el código anterior introducimos llamadas a este método en cada iteración del bucle, el resultado que obtendremos es el mostrado en la animación de abajo, donde se observa que los resultados son enviados al cliente conforme van siendo generados, en lugar de tener que esperar al proceso completo de la vista:
@using System.Threading.Tasks
@{
    Layout = null;
}
<html>
<head>
    <title>Hello world!</title>
</head>
<body>
    <h1>Let's go</h1>
    @await FlushAsync()
    <ul>
        @for (int i = 0; i < 10; i++)
        {
            await Task.Delay(1000);
            <li>@i</li>
            await FlushAsync();
        }
    </ul>
</body>
</html>

Resultado enviándose al cliente de forma progresiva

¿Mola, eh? Pero, ojo, antes de lanzarnos a utilizarlo siempre en nuestras aplicaciones, hay que tener en cuenta que no se trata de la panacea, tiene sus limitaciones. Por ejemplo, no podemos utilizar FlushAsync() en el interior de una página que utilice un Layout debido al extraño orden en el que se ejecutan estos elementos, o tampoco podemos usarlo en el interior de tag helpers.

Publicado en Variable not found.

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