SignalR Hub Protocol

SignalR is an open-source library developed by Microsoft for real-time web communication. It enables developers to build interactive, live-updating web applications by facilitating bidirectional communication between the server and connected clients.

With the HTTP request what we do is, send a request from a client(any device UI not people). Let's say we open up facebook.com, the server will send us the data and the page will be opened with data. Now, unless you give another input, let's say a button click to log in the page won't send a request to the backend. This is called stateless communication (in other words request and response model that is http). So we can think of HTTP as a wall between server and client which only allows entry when a client requests something whereas we can think of signalR as a tunnel where the communication can be both ways, this is called an open connection or consistent connection.

SignalR helps in creating real-time applications like a social media platform that shows feeds from other people as well as you as soon as the information is fed. SignalR uses these four technologies for the real-time behavior:

  • WebSockets

  • Event Source

  • Forever Frame

  • Long Polling

Why do we need SignalR?

We can directly use WebSockets to do the same thing we do with SignalR so the reason why we use SignalR is that SignalR runs on the above four technologies so we do not need to learn all of them only SignalR suffices. It provides an abstraction that is easier to learn and implement.

What is Long Polling?

Instead of a client requesting a server again and again to get any new data, long polling allows to send a request and that request resides in the server until the data is available. Since the server has a memory of a goldfish (it forgets that a request is pending) we have to send alerts to remind the server of the request. Because the request resides in the server, hitting the server to entertain a request, frequently, is avoided. This is not a persistent connection as the connection gets lost after the request is fulfilled

and it is one-way. Though the amount of requests is less they are still not that low so it simulates a persistent connection but it's not fully persistent because the server needs to be reminded of that request frequently and data is not pushed by the server on its own, it is requested by the client.

Normal web calls v Ajax calls v Long Polling

In normal web calls the request is sent and the response if present is sent back after taking the processing time by the server. Then another request same way.

In Ajax calls, the first request is a normal web request and now when the connection is established, with AJAX calls the client does not wait for the response from the server it goes on to do its own thing. The server sends the data back to the client, sometimes there is no data.

In Long Polling, like Ajax calls first request to the server is a normal web request. Now when the connection is formed continuous requests can be sent to the server on the same connection but unlike Ajax, the server waits for the data to be available before the response is sent back and again a new request is sent to the server and so on.

What is WebSockets?

WebSockets is a protocol that helps us create a client-server connection allowing data flow bidirectionally meaning the request and response take place in a full-duplex manner. When the handshaking between the client and server is done that channel is used for all the future requests and responses until one of them decides to end that channel. When that is done the connection between both is terminated making it stateful. It starts from ws:// or wss:// .

Characteristics:

  • bi-directional persistent connection

  • multi-user

  • full-duplex

  • Asynchronous

What is Hub in SignalR?

The SignalR Hubs API enables connected clients to call methods on the server. The server defines methods that are called by the client and the client defines methods that are called by the server. SignalR takes care of everything required to make real-time client-to-server and server-to-client communication possible.

Note: Please refer to these repos:

https://github.com/khan88012/Websocket-SignalR-Chat

https://github.com/khan88012/chat-app

Creating a hub class:

To create a hub class, you need to extend " Microsoft.AspNetCore.SignalR.Hub " class into your custom class.

using Microsoft.AspNetCore.SignalR;

namespace ChatService.Hubs
{
    public class MessageHub : Hub
    {
        public async Task NewMessage(Message msg)
        {
            await Clients.All.SendAsync("MessageReceived", msg);
        }
    }
}

/*
    public class Message
    {
        public string clientuniqueid { get; set; }
        public string type { get; set; }
        public string message { get; set; }
        public DateTime date { get; set; }
    }
*/

Note:

  • The NewMessage task takes the parameter msg from client and broadcasts the same message to all the connected clients in the form of "MessageReceived" event.

How to configure SignalR hubs?

To register signalR hub in your .net 7 web project add the below line in program.cs file/:

builder.Services.AddSignalR();

To configure SignalR endpoint, call MapHub method by passing desired endpoint name:

app.MapHub<MessageHub>("/MessageHub");

Now, when you build and run the project you will see something like this and you are ready to build a client to connect with this hub.

Note: Add CORS policy if you are going to create a client project that is not a part of this solution.

builder.Services.AddCors(options =>
{
    options.AddPolicy("AllowAllHeaders",

        builder =>
        {
            builder.WithOrigins("http://localhost:4200")
                   .AllowAnyHeader()
                   .AllowAnyMethod()
                   .AllowCredentials();
        }


        );
});

app.UseCors("AllowAllHeaders");

Creating a Client-Side Chat Application to understand SignalR behavior:

Let's create an Angular project and install SignalR package '@microsoft/signalr', which is a JavaScript client library for SignalR, a real-time communication framework developed by Microsoft.

npm install @microsoft/signalr

Now create a service to establish the connection:

import { EventEmitter, Injectable } from '@angular/core';
import { Message } from './message';
import { HubConnection, HubConnectionBuilder } from '@aspnet/signalr';

@Injectable({
  providedIn: 'root'
})
export class ChatService {
  chatServiceURL = 'https://localhost:44385/'; // can be changed if backend runs on different port

  messageReceivedHere = new EventEmitter<Message>();  
  connectionEstablished = new EventEmitter<Boolean>();  

  private connectionIsEstablished = false;  
  private _hubConnection!: HubConnection;  

  constructor() {  
    this.createConnection();  
    this.registerOnServerEvents();  
    this.startConnection();  
  }  

  sendMessage(message: Message) { 
    this._hubConnection.invoke('NewMessage', message);  
    console.log("message is ", message);
  }  

  private createConnection() {  
    this._hubConnection = new HubConnectionBuilder()  
    .withUrl(this.chatServiceURL + 'MessageHub')  
    .build();  

  }  

  private startConnection(): void {  
    this._hubConnection  
      .start()  
      .then(() => {  
        this.connectionIsEstablished = true;  
        console.log('Hub connection started');  
        this.connectionEstablished.emit(true);  
      })  
      .catch(err => {  
        console.log('Error while establishing connection, retrying...');  
        setTimeout( () => { this.startConnection(); }, 5000);  
      });  
  }  

  private registerOnServerEvents(): void {  
    this._hubConnection.on('MessageReceived', (data: any) => {  
      this.messageReceivedHere.emit(data);  
    });  
  }  
}
  1. HubConnection: This class is used to create a connection to a SignalR hub. A SignalR hub is a server-side component that handles communication with connected clients. You can use HubConnection to establish a connection to the hub, send messages, and listen for messages from the server.

  2. HubConnectionBuilder: This class is used to build and configure a HubConnection instance. It allows you to set various options and configure the connection before establishing it.

  3. Using the on method of a HubConnection object to listen for a specific event named 'MessageReceived' from the SignalR hub. When this event is received, the provided callback function is executed. In this case, the callback function emits the received data using this.messageReceived.emit(data);.

  4. With the help of invoke method we can send messages to the hub named 'NewMessage'.

Note :

In above example, we're creating a new HubConnection using HubConnectionBuilder, specifying the URL of the SignalR hub with withUrl(), and then starting the connection with start(). After the connection is established, you can use hubConnection to interact with the SignalR hub.