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, 14 de febrero de 2023
Blazor

Hace poco, un alumno de mi curso de Blazor en CampusMVP me preguntaba si, para seguir con las viejas costumbres, desde Blazor Server era posible escribir en la consola del navegador.

Aunque no tiene demasiado sentido hacerlo dado que disponemos de buenas herramientas de depuración, me pareció un ejemplo interesante para aplicar los mecanismos de interoperación de Blazor con JavaScript. Además, quizás interese a alguien más, así que vamos a ver por aquí cómo hacerlo.

Pero antes de meternos en faena, vale la pena decir que lo que veremos no es específico de Blazor Server, sino que también podremos usarlo en Blazor WebAssembly. Los mecanismos básicos de interoperación con JavaScript son idénticos, por lo que en este post veremos cómo implementar un código válido para ambos tipos de hosting.

Enviar mensajes a la consola del navegador, versión básica

Como vimos hace tiempo, la interfaz IJSRuntime ofrece una vía para ejecutar código JavaScript desde C# en nuestros componentes o servicios Blazor.

Basta con inyectar una instancia de este tipo en nuestra clase, y podremos realizar invocaciones directas de código que vive en el lado del cliente, independientemente de si lo estamos ejecutando en el servidor (Blazor Server) o en el cliente (Blazor WebAssembly).

De esta forma, si queremos escribir en la consola, simplemente debemos usar el método InvokeVoidAsync() como se muestra en el siguiente componente Counter.razor:

@page "/counter"
@inject IJSRuntime JsRuntime

<h1>Counter</h1>
<p>Current count: @currentCount</p>

<button @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private async Task IncrementCount()
    {
        currentCount++;
        await JsRuntime.InvokeVoidAsync("console.log", "Yepa! " + currentCount);
    }
}

Observad que usamos InvokeVoidAsync() porque el método JavaScript console.log() no devuelve ningún valor.

En tiempo de ejecución, la pulsación del botón hará que vayan apareciendo mensaje en la consola del navegador, como se muestra en la siguiente imagen:

Consola del navegador mostrando un mensaje enviado desde Blazor (C#)

De la misma forma que llamamos a console.log() de JavaScript, podríamos invocar otros métodos interesantes como error(), warn(), info() u otros.

Por ejemplo, si insertásemos el siguiente código en el ejemplo anterior, podríamos ver en consola el volcado del objeto .NET que estamos enviando en una traza de error:

private async Task IncrementCount()
{
    currentCount++;
    await JsRuntime.InvokeVoidAsync("console.log", "Yepa! " + currentCount);
    if (currentCount > 10)
    {
        var arg = new { error = "Too much clicks", count = currentCount};
        await JsRuntime.InvokeVoidAsync("console.error", arg);
    }
}

Objeto enviado desde C# a la consola en una traza de error

La consola del navegador como servicio

En el ejemplo anterior hemos visto que podemos escribir a la consola del navegador desde C# de forma muy sencilla, aunque podríamos mejorarlo un poco si, en lugar de hacerlo inline, extraemos esta funcionalidad a un servicio que podría ser reutilizado en distintos puntos de la aplicación.

Esto podemos verlo en el siguiente bloque de código, donde definimos una clase llamada ConsoleServices sobre la que creamos métodos que mapean directamente los métodos del objeto console de JavaScript:

public class ConsoleServices
{
    private readonly IJSRuntime _JsRuntime;

    public ConsoleServices(IJSRuntime js)
    {
        _JsRuntime = js;
    }
    public ValueTask Log(params object[] args)
    {
        return _JsRuntime.InvokeVoidAsync("console.log", args);
    }

    public ValueTask Error(params object[] args)
    {
        return _JsRuntime.InvokeVoidAsync("console.error", args);
    }

    // .. otros métodos del objeto console de JavaScript
}

Antes de usar el servicio, debemos registrarlo en el inyector de dependencias de Blazor. Tanto en Server como en WebAssembly tendremos que insertar en el archivo Program.cs la siguiente línea:

builder.Services.AddScoped<ConsoleServices>();

Y a partir de aquí, ya podremos utilizar el servicio en cualquier otro servicio o componente de la aplicación, como muestra la siguiente versión retocada del componente Counter.razor que vimos más arriba:

@page "/counter"
@inject ConsoleServices Console

<h1>Counter</h1>
<p>Current count: @currentCount</p>

<button @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
        Console.Log("Dale! " + currentCount);
    }
}
Publicado en: www.variablenotfound.com.

2 Comentarios:

Anónimo dijo...

Si quisiéramos invocar window.screen que no tiene argumentos usando el Console Service.
¿Cómo se haría?

José María Aguilar dijo...

Hola!

Entiendo que te refieres a retornar el contenido de un objeto como window.screen, ¿verdad? En este caso, no se trata de una función, por lo que no puedes llamarla usando los métodos Invoke() del runtime JS.

Lo más sencillo en estos casos es que insertes en la página una función JS que sea la que devuelva ese valor, algo más o menos así:

window.getScreen = function() {
return window.screen;
}

Y así, desde tu código Blazor podrías llamar sin problema a ese getScreen() para obtener lo que necesitas.

Saludos!