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, 28 de noviembre de 2023
Blazor

Como sabéis, hasta ahora, los componentes Blazor podían ejecutarse en dos tipos de hosting distintos, Blazor Server y Blazor WebAssembly. Aunque cada uno tiene sus escenarios ideales de uso, ambos enfoques conseguían lo mismo, implementar Single Page Applications en C#, sin necesidad de utilizar JavaScript (bueno, o al menos, minimizando radicalmente su uso):

  • Con Blazor Server, se mantiene en el servidor una copia del DOM de cada usuario conectado, de forma que C# puede manipularlo directamente. Luego, mediante una conexión websockets, se sincronizan los cambios con el cliente.
  • Blazor WebAssembly lleva al navegador el runtime de .NET, las bibliotecas base y los ensamblados de la aplicación, por lo que todo se ejecuta directamente en el lado cliente gracias a WebAssembly.

Estas dos formas de ejecutar componentes son muy apropiadas cuando se trata de elementos interactivos, capaces de responder a eventos de usuarios y con capacidad de actualizar el contenido de la página. Sin embargo, son muy poco eficientes cuando se trata de páginas estáticas que no requieren interacción con el usuario:

  • Para poder mostrar en el navegador un contenido, en Blazor Server hay que esperar a que el lado cliente descargue la página contenedora, un archivo JavaScript y se establezca la conexión websockets con el servidor, tras lo cual se enviará el contenido de la página.

  • En Blazor WebAssembly, el cliente debe descargar la página contenedora, los ensamblados y todo el entorno de ejecución de .NET y lanzarlo todo sobre WebAssembly. En este momento se puede mostrar el contenido de la página.

Con ASP.NET Core 8, Blazor añade un tercer tipo de hosting, Server-Side Rendering, que permite a las páginas de Blazor recibir directamente peticiones HTTP, renderizar y retornar el contenido estático al navegador. En este caso, no es necesario establecer una conexión websockets, ni descargar el runtime de .NET, porque lo que se envía al lado cliente es HTML puro, el resultante de renderizar los componentes Razor en el servidor. Vaya, algo muy similar a lo que ocurre cuando accedemos a páginas generadas con ASP.NET Core MVC, Razor Pages o cualquier otro framework de backend.

Es decir, en la práctica, se trata de un mecanismo que nos permite generar páginas completas usando la fantástica sintaxis, potencia y productividad del modelo de componentes de Blazor.

Con ello conseguimos un objetivo muy deseado: hacer de Blazor un framework de desarrollo web fullstack, que nos permitirá implementar cualquier tipo de aplicación web, desde SPAs ricas, dinámicas e interactivas, hasta sitios web eminentemente estáticos, como páginas corporativas, blogs, foros, etc., donde no es necesaria una interacción tan cercana al usuario y el SEO es un factor importante.

Obviamente, si usamos Server-Side Rendering no podemos manipular el DOM ni implementar ningún tipo de comportamiento interactivo. Por ejemplo, imagina una página Blazor como la siguiente:

@page "/counter"

<p>Current: @count</p>
<button @onclick="()=>count++">Click!</button>

@code {
    int count = 0;
}

Esta página será mostrada correctamente en el navegador con el valor inicial de counter y un botón, pero no responderá al evento onclick. Blazor SSR simplemente se encarga de retornar muy rápidamente al navegador contenido estático, que además será fácil de indexar por parte de los buscadores y otros bichos que rastrean la web.

Adicionalmente, en Blazor SSR se han incluido algunas mejoras progresivas para hacer la experiencia de usuario más fluida durante su navegación por las páginas y en el uso de formularios, pero lo veremos en otro post más adelante.

Si necesitamos componentes interactivos, podemos combinar Blazor Server-Side Rendering con Blazor Server o Blazor WebAssembly de forma muy sencilla, porque estaremos hablando en todo momento el mismo idioma: al final todo son componentes Razor. Simplemente, algunos de ellos se ejecutarán de forma estática en el servidor, y otros en el lado cliente (usando el hosting WebAssembly o Server según las necesidades concretas de cada caso).

Por ejemplo, si queremos que en una página renderizada con Blazor SSR se incluya un componente interactivo con renderizado en servidor (Blazor Server), bastará con indicarlo en el momento de su instanciación mediante el atributo @rendermode:

@page "/"

<p>
    Este texto se renderiza estáticamente (SSR), 
    pero lo siguiente es un componente interactivo.
</p>

<Counter @rendermode="InteractiveServer"></Counter>

De la misma forma, podemos indicar que un componente sea ejecutado en el lado cliente (Blazor WebAssembly), o incluso que sea el propio sistema el que decida si llevarlo al cliente o renderizarlo en el servidor, la opción que sea más rápida en cada momento.

Estas opciones requieren configuraciones adicionales en el Program.cs y tener en cuenta algunos detalles más.

Primer vistazo a una aplicación Blazor SSR simple

Veamos un ejemplo de la pinta que tiene todo esto a nivel de código. Para ello, vamos a crear una Aplicación Blazor Server-Side Rendering desde cero, usando la línea de comandos (obviamente, necesitaremos tener instalado el SDK de .NET 8):

D:\MyFirstSSRApp>dotnet new blazor --interactivity none
The template "Blazor Web App" was created successfully.
This template contains technologies from parties other than Microsoft, 
see https://aka.ms/aspnetcore/8.0-third-party-notices for details.

Processing post-creation actions...
Restoring D:\MyFirstSSRApp\MyFirstSSRApp.csproj:
  Determining projects to restore...
  Restored D:\MyFirstSSRApp\MyFirstSSRApp.csproj (in 118 ms).
Restore succeeded.

D:\MyFirstSSRApp>_

También podemos hacerlo desde Visual Studio, usando la nueva plantilla "Blazor Web App" e indicando que no deseamos incluir componentes interactivos.

Si acudimos al archivo Program.cs, veremos que el código de inicialización es muy parecido al de cualquier otra aplicación ASP.NET Core (de hecho, porque es una aplicación ASP.NET Core 😉). Las únicas novedades destacables las encontramos en las llamadas a AddRazorComponents() y MapRazorComponents<App>():

using MyFirstSSRApp.Components;

var builder = WebApplication.CreateBuilder(args);

// Novedad 1:
builder.Services.AddRazorComponents();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error", createScopeForErrors: true);
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles();
app.UseAntiforgery();

// Novedad 2:
app.MapRazorComponents<App>();

app.Run();

Como podréis intuir, con AddRazorComponents() registramos en el inyector de dependencias los servicios necesarios para poder renderizar componentes Razor en el servidor.

Más abajo, con MapRazorComponents<App>() se descubren los componentes disponibles en la aplicación, y se especifica el componente raíz, que en este caso es <App>. Observad que, a diferencia de los otros hostings de Blazor (Server y WebAssembly), no hace falta una página que actúe como host para indicar el componente raíz de la aplicación, ya lo estamos haciendo en la propia de inicialización.

El código del componente <App>, que hemos indicado que es el componente raíz de la aplicación, está disponible en el archivo  App.razor, e incluye el esqueleto de la página HTML que se enviará al navegador además de:

  • El clásico componente <HeadOutlet>, que nos permitirá introducir contenido en el encabezado
  • El componente <Routes> que cargará el sistema de routing y actuará como placeholder de los componentes que irá cargando el sistema de routing de Blazor.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <base href="/" />
    <link rel="stylesheet" href="bootstrap/bootstrap.min.css" />
    <link rel="stylesheet" href="app.css" />
    <link rel="stylesheet" href="MyFirstSSRApp.styles.css" />
    <link rel="icon" type="image/png" href="favicon.png" />
    <HeadOutlet />
</head>

<body>
    <Routes />
    <script src="_framework/blazor.web.js"></script>
</body>
</html>

El componente <Routes> es el encargado de cargar los componentes Razor de tipo página cuya ruta corresponda a la solicitada en la petición:

<Router AppAssembly="@typeof(Program).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(Layout.MainLayout)" />
        <FocusOnNavigate RouteData="@routeData" Selector="h1" />
    </Found>
</Router>

A partir de aquí, todo son las páginas y componentes Razor habituales. Por ejemplo, la página de inicio está definida en el componente Home.razor de la siguiente forma:

@page "/"
<PageTitle>Home</PageTitle>
<h1>Hello, world!</h1>
Welcome to your new app.

Como podéis ver, salvo el código de inicialización, ¡son todo componentes Razor!

En definitiva...

En este post hemos echado un vistazo de alto nivel a Blazor Server-Side Rendering, el nuevo modelo de renderizado de componentes Razor destinado a convertir el framework en una verdadera solución fullstack.

Obviamente hay mucho más de lo que hemos visto aquí, pero creo que de momento es suficiente para al menos saber de qué va y qué podemos esperar de esta interesante novedad de la la versión más reciente de Blazor.

Publicado en: www.variablenotfound.com.

2 Comentarios:

Juan dijo...

Para que Blazor se pueda convertir en una opción mainstream necesita del SEO y eso con WebAssembly y Blazor Server era imposible de conseguir.

Para aplicaciones empresariales (intranet) el SEO es irrelevante, pero cuando desarrollas para el público necesitas que te encuentren con facilidad.

Un saludo.

José María Aguilar dijo...

Hola!

En efecto, el SEO es clave en muchos escenarios.

Con Blazor Server y WASM podías hacerlo usando prerenderización; ahora con Server-Side Rendering es más directo, aunque en el fondo la tecnología es la misma. Pero lo importante es que el contenido de la página se genera en el servidor y se envía al cliente por completo, de forma que puede ser indexado por los buscadores sin problema.

Gracias por comentar!