serving the solutions day and night

Pages

Sunday, August 23, 2020

ASP.NET Core SignalR Application

https://github.com/mkader/SignalRExample

Create a new ASP.NET Core (3.1 or later ) Web Application (whatsupchat) with HTTPS

Add the JavaScript SignalR Client Library.


  • wwwroot -> js -> Right-click and select Add > Client-Side Library
  • Set the Provider to unpkg. 
  • Enter @microsoft/signalr@latest in the Library field. 
    • Select the Choose specific files radio button, 
    • Select dist/browser/signalr.js and signalr.min.js
  • Click Install

The signalr.min.js is a minified file, takes out all the whitespace and carriage returns, creates a smaller file size, resulting in faster response times and lower bandwidth usage.

Create the hub (will handle client-server communication) whatsupchat\Hubs\WhatsupChatHub.cs class 

using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR;
namespace whatsupchat.Hubs;
{
    public class WhatsupChatHub : Hub
    {
     public async Task MessageSender(string user, string message)
     {
        await Clients.All.SendAsync("MessageReceiver", user, message);
    }
   }
}

"Clients.All" property that invokes a method on all the clients connected to this hub.

The MessageSender method is called by a connected client and will send a message to all the clients. 

Configuring SignalR, In Startup Class

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

public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
...
app.UseEndpoints(endpoints => {      
endpoints.MapRazorPages();      
endpoints.MapHub<Hubs.WhatsupChatHub>("/WhatsupChatHub"); }
); 

Configuring the Client Application

index.cshtml

@page  
<form>     
    <div class="form-group">         
        <label for="nameInput">Name</label>         
        <input class="form-control" placeholder="Enter your name" type="text" id="nameInput" />     
    </div>     
    <div class="form-group">         
        <label for="messageInput">Message</label>         
        <input class="form-control" placeholder="Type your message" type="text" id="messageInput" />     
    </div>     
    <div class="form-group">         
        <input class="btn btn-primary" type="button" id="sendButton" value="Send" />    
    </div> 
</form>

<div class="row">     
    <div class="col-12">         <hr />     </div> 
</div> 
<div class="row">     
    <div class="col-6">         
        <ul class="list-group" id="messagesList"></ul>     
    </div> 


<script src="~/js/microsoft/signalr/dist/browser/signalr.js"></script>
<script src="~/js/chat.js"></script>

messagesList that will display all the messages received from the SignalR hub. 

Chat.js

"use strict";

var connection = new signalR.HubConnectionBuilder().withUrl("/WhatsupChatHub").build();

//Disable send button until connection is established. document.getElementById("sendButton").disabled = true; 

connection.on("MessageReceiver", function (user, message) {
    var msg = message.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
    var encodedMsg = user + ": " + msg;
    var li = document.createElement("li");

    var currentUser = document.getElementById("nameInput").value;
    if (currentUser === user) {
        li.className = "list-group-item list-group-item-primary";
    }
    else {
        li.className = "list-group-item list-group-item-success";
    }
    li.textContent = encodedMsg;
    document.getElementById("messagesList").appendChild(li);
});

connection.start().then(function () {
    document.getElementById("sendButton").disabled = false;
}).catch(function (err) {
    return console.error(err.toString());
});

document.getElementById("sendButton").addEventListener("click", function (event) {
    var user = document.getElementById("nameInput").value;
    var message = document.getElementById("messageInput").value;
    connection.invoke("MessageSender", user, message).catch(function (err) {
        return console.error(err.toString());
    });
    event.preventDefault();
});

This JavaScript does three things: 
  • It creates and starts a connection. 
  • It creates an event handler for the Submit button that sends messages to the hub. 
  • It adds an event handler to the connection object that receives messages from the hub and adds those received messages to the message list. 
Running the Application 

Open 2 browser, send message from both browser. The message is immediately displayed in the list at the bottom of the browser page on browser 1/2

Issue with SendAsync

The SendAsync method relies on a string to specify the client method name to be called. 

[await Clients.All.SendAsync("MessageReciever", user, message); ] Compare 

[await Clients.All.SendAsync("MessageReceiver", user, message);] 

 "MessageReciever" is spell mistake, this will open to runtime errors, which aren’t caught at compile time. 

The solution is to use strongly typed hubs(Hub<T>). 
IChatClient.cs 

using System.Threading.Tasks;

namespace whatsupchat.Hubs
{
    public interface IWhatsupChatClient
    {
Task MessageReceiver(string user, string message); 
    }
}

Modification in WhatsupChatHub.cs
    public class WhatsupChatHub : Hub<IWhatsupChatClient> 
    { 
        public async Task MessageSender(string user, string message) 
        { 
            await Clients.All.MessageReceiver(user, message); 
        } 
        } 

No comments: