Crear aplicaciones en tiempo real con Blazor y SignalR


Blazor es uno de los frameworks para Web Assembly mas avanzados del momento y por otra parte SignalR es una librería ligera y fácil de implementar, que nos permite incorporar comunicación en tiempo real dentro de nuestras apps, en este post aprenderemos como combinar estas 2 tecnologías.

Como es usual lo primero que debemos hacer es instalar la librería de SignalR y configurar nuestro hub:

Podemos hacerlo desde el gestor de NuGets con Visual Studio o podemos utilizar el comando en la consola:

Install-Package Microsoft.AspNetCore.SignalR -Version 1.1.0

Debemos configurar SignalR de una manera general en el proyecto agregando el middleware y utilizando services.AddSignalR(); y endpoints.MapHub(“/chat”); en Startup.cs

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();
        services.AddSignalR();

        services.AddResponseCompression(opts =>
        {
            opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(
                new[] { "application/octet-stream" });
        });

        services.AddCors(options => options.AddPolicy("CorsPolicy", builder =>
        {
            builder
                .AllowAnyMethod()
                .AllowAnyHeader()
                .AllowAnyOrigin();
        }));
    }

       public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseCors("CorsPolicy");

            app.UseResponseCompression();

            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
                endpoints.MapHub<ChatHub>("/chat");
            });


        }

Luego configuramos los métodos de nuestro hub, en este caso vamos a crear uno para manejar un simple chat es decir los métodos SendMessage y RecieveMessage y vamos a implementar los métodos OnConnectedAsync y OnDisconnectedAsync para enviar un mensaje cuando se conectan los usuarios y otro para cuando se desconectan

public class ChatHub : Hub<IChatHub>
{
    public async Task SendMessage(ChatMessage chatMessage)
    {
        await Clients.All.RecieveMessage(chatMessage);
    }

    public override async Task OnConnectedAsync()
    {
        await Clients.Client(Context.ConnectionId).RecieveMessage(new ChatMessage() { User = "Host", Message = "Welcome" });
        await base.OnConnectedAsync();
    }

    public override async Task OnDisconnectedAsync(Exception exception)
    {
        await Clients.All.RecieveMessage(new ChatMessage() { User = "Host", Message = Context.ConnectionId + " left" });
        await base.OnDisconnectedAsync(exception);
    }

}

 public interface IChatHub
    {
        Task SendMessage(ChatMessage chatMessage);
        Task RecieveMessage(ChatMessage chatMessage);
    }

El modelo que vamos a usar para la transferencia de datos entre cliente-servidor y servidor-cliente en tiempo real será ChatMessage esta seria la implementación de esta clase:

public class ChatMessage
{
    public string User { get; set; }
    public string Message { get; set; }
}

Una vez tengamos toda esta implementación para nuestro hub vamos a poder fácilmente implementar el cliente utilizando la librería cliente de SignalR. También podemos hacerlo desde la consola de comandos de la siguiente manera:

Install-Package Microsoft.AspNetCore.SignalR.Client -Version 3.1.5

Por ultimo implementamos el código del cliente. Como lo había dicho antes, seria un simple chat, tendremos entonces 2 cajas de texto uno para el usuario otro para el mensaje y 2 botones uno para conectarse y otro para enviar el mensaje

@using Microsoft.AspNetCore.SignalR.Client
@implements IDisposable
<h2>Welcome to my Chat</h2>
<div class="container col-6">
        <div class="form-group">
            <label class="col-form-label">User:</label>
            <input class="form-control" type="text" id="userInput" @bind="@myCurrentMessage.User" />
            <label class="col-form-label">Message:</label>
           <input class="form-control" type="text" id="messageInput" @bind="@myCurrentMessage.Message" />
        </div>
        <div class="form-group">
            <button class="btn-primary" type="button" @onclick="Send" disabled="@(!IsConnected)">Enviar</button>
            <button class="btn-danger" type="button"  @onclick="Disconnect" disabled="@(!IsConnected)">Desconectar</button>
        </div>
        <div style="height:150px; max-height:150px; overflow-y:scroll " >
            <ul class="list-group" id="messagesList">
                @foreach (var message in myMessagesRecieved)
                {
                    <li class="list-group-item">@message.User: @message.Message</li>
                }
            </ul>
        </div>
</div>

@code {

private HubConnection hubConnection;
public List<ChatMessage> myMessagesRecieved;
public ChatMessage myCurrentMessage;

protected override async Task OnInitializedAsync()
{
    myCurrentMessage = new ChatMessage();

    myMessagesRecieved = new List<ChatMessage>();

    hubConnection = new HubConnectionBuilder()
                        .WithUrl("http://localhost:55643/chat")
                        .Build();

    hubConnection.On<ChatMessage>("RecieveMessage", (chatMessage) =>
    {
        myMessagesRecieved.Insert(0, chatMessage);
        StateHasChanged();
    });

    await hubConnection.StartAsync();
}

async Task Send() {
    await hubConnection.SendAsync("SendMessage", myCurrentMessage);
    myCurrentMessage.Message = "";
    StateHasChanged();
}

async Task Disconnect()
{
    await hubConnection.StopAsync();
    myMessagesRecieved.Insert(0, new ChatMessage() { User ="Host", Message = "You left" });
    StateHasChanged();
}

public bool IsConnected =>
hubConnection.State == HubConnectionState.Connected;

public void Dispose()
{
    _ = hubConnection.DisposeAsync();
}

}

Este chat es el ejemplo mas simple que podemos tener, pero es realmente satisfactorio ver como podemos tener esta interacción en tiempo real de una manera tan simple, ejemplos mas avanzados se construirían de la misma forma con el mismo concepto:

Encuentra el repositorio completo de este ejemplo y otros demos con Blazor y SignalR en el siguiente enlace: https://github.com/Mteheran/BlazorRealTime.

Un comentario sobre “Crear aplicaciones en tiempo real con Blazor y SignalR

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión /  Cambiar )

Google photo

Estás comentando usando tu cuenta de Google. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

Conectando a %s