En Mi Local Funciona

Technical thoughts, stories and ideas

Introducción a Blazor con .NET Core 3.0 (Parte 3): Aplicaciones Blazor ServerApp

Publicado por Santi Macias el

Microsoft.NET CoreBlazorSPA

Como vimos en el primer y segundo artículo sobre Blazor, se trata de un nuevo framework open-source diseñado por Microsoft que viene incluido de forma oficial en la nueva versión de .NET Core 3.0 para crear Single Page Applications (SPA) en el mundo .NET utilizando Razor y C# en lugar de Javascript.

En este tercer artículo, explicaremos como configurar un certificado válido en nuestro equipo y utilizaremos Visual Studio Code para el desarrollo front-end mediante el modelo Blazor Server Apps, para entender las diferencias con el modelo Blazor Cliente y como desarrollar aplicaciones web del lado servidor.

Certificados en aplicaciones ASP.NET Core

La primera vez que instalamos y utilizamos .NET Core el SDK se encarga de generar un certificado en nuestro equipo, pero este certificado generalmente no es válido y hay que realizar manualmente el proceso de confianza.

Al tratarse de una aplicación de servidor (ServerApp) necesitamos disponer de un certificado válido en nuestro entorno de desarrollo. Si no lo tenemos, al internar ejecutarla fallará y obtendremos el siguiente error:

Unable to start Kestrel - System.InvalidOperationException:  
Unable to configure HTTPS endpoint.  
No server certificate was specified, and the default developer certificate could not be found or is out of date.  
To generate a developer certificate run 'dotnet dev-certs https'.  
To trust the certificate (Windows and macOS only) run 'dotnet dev-certs https --trust'.  
For more information on configuring HTTPS see https://go.microsoft.com/fwlink/?linkid=848054.  

En el caso de trabajar con una distro de Linux, se deberá revisar como configurar el certificado en vuestro equipo, consultando la documentación de cada fabricante o distribución.

Configurando certificados válidos en ASP.NET Core

En .NET Core, disponemos del comando dotnet dev-certs https --help para gestionar certificados en el equipo de desarrollo. Veamos las opciones disponibles:

C:\ReposEMLF> dotnet dev-certs https --help  
Usage: dotnet dev-certs https [options]

Options:  
  -ep|--export-path  Full path to the exported certificate
  -p|--password      Password to use when exporting the certificate with the private key into a pfx file
  -c|--check         Check for the existence of the certificate but do not perform any action
  --clean            Cleans all HTTPS development certificates from the machine.
  -t|--trust         Trust the certificate on the current platform
  -v|--verbose       Display more debug information.
  -q|--quiet         Display warnings and errors only.
  -h|--help          Show help information

Con la opción --check averiguamos si nuestro certificado es válido:

C:\ReposEMLF>dotnet dev-certs https --check  
No valid certificate found.  

Con la opción --clean, borramos los certificados actuales. Nos mostrará un dialogo con el certificado encontrado y pedirá confirmación para continuar:

C:\ReposEMLF>dotnet dev-certs https --clean  
Cleaning HTTPS development certificates from the machine. A prompt might get displayed to confirm the removal of some of the certificates.  
HTTPS development certificates successfully removed from the machine.  

A continuación, creamos el nuevo certificado de confianza mediante la opción --trust. Nos aparecerá un dialogo con el nuevo certificado y pedirá confirmación para continuar:

C:\ReposEMLF>dotnet dev-certs https --trust  
Trusting the HTTPS development certificate was requested. A confirmation prompt will be displayed if the certificate was not previously trusted. Click yes on the prompt to trust the certificate.  
The HTTPS developer certificate was generated successfully.  

De nuevo, con la opcion --check volvemos a comprobar si ya tenemos un certificado válido:

C:\ReposEMLF>dotnet dev-certs https --check  
A valid certificate was found.  

Ahora ya podemos continuar con la creación de la aplicación Blazor.

Creando nuestra primera aplicación Blazor Server App

En esta ocasión, vamos a crear una aplicación basada en la plantilla blazorserver que funciona mediante el modelo servidor de .NET Core y SignalR, es decir, no utilizará WebAssembly en el navegador del usuario.

Desde la consola escribimos estos comandos de .NET Core y voy a llamar a la aplicación BlazorServerSPA.

dotnet new blazorserver -o BlazorServerSPA

cd BlazorServerSPA

dotnet build

dotnet run  

Una vez ejecutados los comandos veremos esto en la consola:

C:\ReposEMLF>dotnet new blazorserver -o BlazorServerSPA  
The template "Blazor Server App" was created successfully.  
This template contains technologies from parties other than Microsoft, see https://aka.ms/aspnetcore/3.0-third-party-notices for details.

Processing post-creation actions...  
Running 'dotnet restore' on BlazorServerSPA\BlazorServerSPA.csproj...  
  Restauración realizada en 49,03 ms para C:\ReposEMLF\BlazorServerSPA\BlazorServerSPA.csproj.

Restore succeeded.

C:\ReposEMLF>cd BlazorServerSPA

C:\ReposEMLF\BlazorServerSPA>dotnet build  
Microsoft (R) Build Engine versión 16.3.0+0f4c62fea para .NET Core  
Copyright (C) Microsoft Corporation. Todos los derechos reservados.  
  Restauración realizada en 16,31 ms para C:\ReposEMLF\BlazorServerSPA\BlazorServerSPA.csproj.
  BlazorServerSPA -> C:\ReposEMLF\BlazorServerSPA\bin\Debug\netcoreapp3.0\BlazorServerSPA.dll
  BlazorServerSPA -> C:\ReposEMLF\BlazorServerSPA\bin\Debug\netcoreapp3.0\BlazorServerSPA.Views.dll

Compilación correcta.  
    0 Advertencia(s)
    0 Errores
Tiempo transcurrido 00:00:03.66

C:\ReposEMLF\BlazorServerSPA>dotnet run  
info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0]  
      User profile is available. Using 'C:\Users\HP\AppData\Local\ASP.NET\DataProtection-Keys' as key repository and Windows DPAPI to encrypt keys at rest.
info: Microsoft.Hosting.Lifetime[0]  
      Now listening on: https://localhost:5001
info: Microsoft.Hosting.Lifetime[0]  
      Now listening on: http://localhost:5000
info: Microsoft.Hosting.Lifetime[0]  
      Application started. Press Ctrl+C to shut down.

Ya tenemos corriendo la aplicación Blazor, en este caso en http://localhost:5000 y https://localhost:5001. En realidad si conectamos por el puerto 5000 nos reenviará al puerto 5001 donde tenemos la conexión con el certificado local que hemos comentado al principio.

Si abrimos la URL http://localhost:5000, nos enviará a la ruta https://localhost:5001 donde veremos una pantalla de Advertencia de seguridad del certificado con aspecto como esta imagen.

El navegador nos informa que No se confía en el certificado porque está autofirmado. Este mensaje aparece porque el certificado es un certificado local que hemos creado nosotros mismos, por lo que solo nos falta aceptarlo y aparecerá la aplicación Blazor con el menú principal y el mensaje Hello World!

Vamos a ver el código fuente generado en el siguiente apartado.

Revisando el código fuente con Visual Studio

Comprobemos el código fuente generado y la estructura de la aplicación Blazor que acabamos de crear. Si lo comparamos con el artículo de la parte 2, cambia mucho la forma de configurar los servicios.

En la clase Program.cs vemos el método Main, punto de entrada de la aplicación donde se crear el HostBuilder usando la llamada a UseStartup.

En la clase Startup.cs encontramos los métodos para registrar y configurar nuestros servicios en .NET Core donde se añaden los diferentes servicios para configurar el Servidor de Razor.

La linea endpoints.MapBlazorHub es la que define el servidor de SignalR para comunicar el cliente y poder realizar las interacciones del usuario en el navegador.

En el archivo BlazorServerSPA.csproj tenemos solo las referencias a librerías netcoreapp 3.0:

<Project Sdk="Microsoft.NET.Sdk.Web">  
  <PropertyGroup>
   <TargetFramework>netcoreapp3.0</TargetFramework>
  </PropertyGroup>
</Project>  

En la clase App.razor encontramos la definición para las rutas:

<Router AppAssembly="@typeof(Program).Assembly">  
    <Found Context="routeData">
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
    </Found>
    <NotFound>
        <LayoutView Layout="@typeof(MainLayout)">
            <p>Sorry, there's nothing at this address.</p>
        </LayoutView>
    </NotFound>
</Router>  

En la clase _Imports.razor encontramos las referencias a librerías para importar los componentes y JSInterop:

@using System.Net.Http
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.JSInterop
@using BlazorServerSPA
@using BlazorServerSPA.Shared

En la carpeta wwwroot, hay una diferencia importante ya que no existe index.html. En su lugar revisa la carpeta Pages donde se encuentra _Host.cshtml con el código HTML inicial para cargar nuestra web cuando accedemos desde el navegador. Esto se especifica en la clase Startup.

Fijaos también en el link: "framework/blazor.server.js". donde ha cambiado la referencia con respecto al modelo basado en webassembly "framework/blazor.webassembly.js".

@page "/"
@namespace BlazorServerSPA.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<!DOCTYPE html>  
<html lang="en">  
<head>  
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>BlazorServerSPA</title>
    <base href="~/" />
    <link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
    <link href="css/site.css" rel="stylesheet" />
</head>  
<body>  
    <app>
        @(await Html.RenderComponentAsync<App>(RenderMode.ServerPrerendered))
    </app>

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

En las carpeta Pages y Shared encontramos, los archivos con la nueva extensión .razor que son los componentes donde está el código HTML5, los layouts de las páginas, el sistema de rutas y código de C# que se debe ejecutar.

Los archivos de estas carpetas se corresponden con menú de opciones de nuestra web utilizando el sistema de rutas que se define en la directiva @page para cada una de las páginas y en la directiva @code está el código C# que se ejecutará:

Como en el segundo artículo de Blazor, el componente counter.razor, es exactamente el mismo: por una lado el código de la página (@page), por otro el código C# (@code) y existe un botón con evento onclick, apuntando al método IncrementCount. Este botón es HTML y su función de onclick está invocando al método escrito en C#.

Probad a cambiar el valor del incremento y compilad de nuevo para ver cómo funciona.

Revisando la ejecución en navegador

Con la aplicación en marcha, miramos el código fuente de la página inicial, activando las herramientas de desarrollo en nuestro browser favorito para inspeccionar el codigo HTML y vemos la referencia al "_framework/blazor.server.js".

Ahora, si nos vamos a la pestaña de network/red en las herramientas de desarrollo y refrescamos de nuevo la página principal, fijaos en todo lo descargado para poder ejecutar la app en el navegador.

Al tratarse de una aplicación en modelo servidor (basado en SignalR con websocket) no aparece ninguna referencia de WebAssembly, Mono ni tampoco nuestro proyecto BlazorServer.dll y sus dependencias, cosa que si ocurría en el modelo de aplicaciones cliente con WebAssembly.

En el artículo inicial sobre los fundamentos de Blazor, encontrareis la explicación técnica de cómo funciona este modelo de aplicaciones y su procesamiento en el navegador mediante SignalR.

Conclusiones

En este artículo, hemos visto como utilizar los certificados en aplicaciones ASP.NET Core y la forma de crear aplicaciones web Single Page Applications (SPA), mediante el modelo de servidor de Blazor basado en SignalR (sin utilizar WebAssembly) y los cambios con respecto al funcionamiento en los navegadores web modernos.

Como explicamos en artículos anteriores, la adopción y transición a Blazor para los desarrolladores ASP.NET MVC/Core y Razor es muy suave porque los conceptos generales son iguales.

Si te ha gustado el articulo, ¡Síguenos en Twitter y no te pierdas los próximos posts sobre Blazor!

Santi Macias
Autor

Santi Macias

Microsoft Tech Lead en atSistemas, +20 años trabajando con tecnologías Microsoft actualmente centrado sobretodo en Azure, Cloud Native, DevOps, Docker, Kubernetes, Microservicios y Serverless.