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, 8 de junio de 2021
Blazor

Blazor permite crear componentes que son ignorantes respecto al modelo de hosting que están utilizando en tiempo de ejecución. Es decir, si lo diseñamos apropiadamente, un componente podría funcionar indistintamente en Blazor Server y Blazor WebAssembly, lo cual sería ideal desde el punto de vista de su reutilización.

Sin embargo, desde el interior de estos componentes, a veces necesitaremos distinguir cuándo están siendo ejecutados en Blazor Server y cuándo en Blazor WebAssembly. ¿Cómo podemos conseguir esto? Pues tenemos muchas maneras...

1. Consultando el valor de RuntimeInformation.OSDescription

Probablemente sea la fórmula más sencilla, pues basta con examinar determinadas propiedades estáticas de la clase System.Runtime.InteropServices.RuntimeInformation, diseñada para proporcionar datos sobre el entorno en el que está corriendo una aplicación.

En particular, la propiedad OSDescription contendrá el valor "Browser" cuando estemos ejecutando el componente en Blazor WebAssembly, por lo que podemos determinar el modelo de ejecución de forma trivial:

@using System.Runtime.InteropServices

@if (IsWasm) 
{
    <p>Hello from Blazor WebAssembly</p>
} 
else 
{
    <p>Hello from Blazor Server</p>
}

@code {
    private bool IsWasm => RuntimeInformation.OSDescription == "Browser";
}

A través del mismo RuntimeInformation podemos consultar también otras propiedades que cambiarán dependiendo del tipo de host. Por ejemplo, la propiedad RuntimeIdentifier valdrá "browser-wasm" en Blazor WebAssembly, mientras que en Blazor Server contendrá el identificador del sistema operativo seguido de la arquitectura (por ejemplo "win10-x64").

2. Consultando el tipo del objeto de interoperación con Javascript

Esta técnica es también muy sencilla. El truco aquí consiste en inyectar en el componente un objeto de tipo IJSRuntime que, como sabemos, es la abstracción que nos permite acceder a los mecanismos de interoperación con Javascript en tiempo de ejecución.

Pues bien, dado que cada modelo de hosting utiliza por detrás una implementación distinta de la interfaz IJSRuntime, podemos determinar el modelo de ejecución simplemente comprobando el tipo concreto, a día de hoy:

  • RemoteJSRuntime en el caso de Blazor Server
  • DefaultWebAssemblyJSRuntime en Blazor WebAssembly

Sin embargo, estas clases son internas y podrían ser modificadas más adelante, por lo que no nos interesaría atarnos a ellas. Aún mejor, podemos consultar simplemente si el objeto IJSRuntime recibido implementa IJSInProcessRuntime, algo que sólo ocurrirá en Blazor WebAssembly. Dado que esta interfaz pertenece a la API pública, podemos estar seguros de que será una solución definitiva.

Por tanto, finalmente podríamos tener un código así:

@using Microsoft.JSInterop
@inject IJSRuntime JsRuntime

@if (IsWasm)
{
    <p>Hello from Blazor WebAssembly</p>
}
else
{
    <p>Hello from Blazor Server</p>
}

@code {
    private bool IsWasm => JsRuntime is IJSInProcessRuntime;
}

3. Usando inyección de dependencias

Por último, si queremos una solución completamente gestionada desde nuestra parte, también podríamos implementarla muy rápidamente mediante inyección de dependencias.

Para ello, lo primero que tendríamos que hacer es definir en nuestro componente compartido una interfaz común que nos dará acceso al servicio que determinará el tipo de host, como la siguiente:

public interface IBlazorHostProperties
{
    bool IsWasm { get; }
    bool IsServer { get; }
}

Esta interfaz podría encontrarse definida, por ejemplo, en el ensamblado donde se implemente el componente, referenciado por los proyectos Blazor Server y WebAssembly que lo vayan a consumir.

Luego, en proyectos Blazor Server introduciríamos la siguiente clase, que sería la implementación específica de la interfaz para este modelo de hosting:

public class BlazorServerHostProperties: IBlazorHostProperties
{
    public bool IsWasm => false;
    public bool IsServer => !IsWasm;
}

Por último, registraríamos la clase como singleton en el inyector de dependencias, en el método ConfigureServices() de la clase Startup:

services.AddSingleton<IBlazorHostProperties, BlazorServerHostProperties>();

De la misma forma, en proyectos Blazor WebAssembly crearíamos su implementación específica de IBlazorHostProperties:

public class BlazorWasmHostProperties : IBlazorHostProperties
{
    public bool IsWasm => true;
    public bool IsServer => !IsWasm;
}

Y la registraríamos igualmente en el inyector, esta vez en la clase Program:

builder.Services
       .AddSingleton<IBlazorHostProperties, BlazorWasmHostProperties>();

Una vez hecho esto, ya desde nuestros componentes compartidos podríamos requerir una instancia de IBlazorHostProperties y usarla para determinar el modo de ejecución.

@inject IBlazorHostProperties BlazorHostProperties

@if (BlazorHostProperties.IsWasm)
{
    <p>Hello from Blazor WebAssembly</p>
}
else
{
    <p>Hello from Blazor Server</p>
}

Y esto es todo :) De esta forma, cuando ejecutemos el componente en Blazor Server, el objeto que nos llegará será un BlazorServerHostProperties, mientras que si lo hacemos en WebAssembly será BlazorWasmHostProperties, y cada uno de ellos nos proporcionará el valor correcto para las propiedades IsWasm e IsServer.

¡Espero que os sea de ayuda!


Publicado en: www.variablenotfound.com.

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