SignalR In .NET Core

Introduction 

 
Dear reader, as we know nowadays, real-time data communication is one of the major parts of software development.
 
As we know, Microsoft provided one of the great technology that is SignlRIt is one of the most important topics for real-time data communication. Sometimes we are required to get up-to-date data without doing any action by the end user, in this case, signalR helps us.
 
In this article, I will try to explain an overview of SignalR in .NET core.
 
Based on that I have categories in the following ways:
  • Overview
  • Architecture
  • Goals
  • Implementation
  • Dependencies
  • References

Overview

 
SignalR is a data notification service and it is an open-source provided by Microsoft that help us for real-time web functionality to apps.
 
Real-time web functionality means that it sends server-side messages to push client-side without any user action. It also allows us to send data from the client to server when they are connected to each other.
 
This kind of communication is managed through protocols, There are three kinds of protocols that signalR uses:
 
In these protocols, WebSocket is one of the most and default protocols.
 
SignalR uses in many application scenario, in this case, this is best for such kind of applications.
  • Chat applications
  • Project management tools
  • Online gaming
  • Automatic updating of applications
  • Notifications and alerts
There are the following features that we will cover in this section:
  • It handles connection management automatically.
  • Sends messages to all connected clients simultaneously.
  • Sends messages to specific clients or groups of clients.
  • Scales to handle increasing traffic using a load balancer.
Transports 
 
SignalR supports many ways of handling real-time data communications:
  • WebSockets
  • Server-Sent Events
  • Long Polling
  • It automatically chooses the best transport method. The default is a websocket that has the capabilities of the server and client for mutual.
Hubs
 
SignalR uses hubs class to communicate between clients and servers.
 
A hub is a high-level pipeline class that allows a client and server to call methods to each other. SignalR handles the data communication across multiple boundaries automatically, it allows the clients to call methods which is available on the server and vice versa.
 
The Hub class contains Context property and many more, which further provides other information about the connection, such as:
  • ConnectionAborted
  • ConnectionId
  • Features
  • Items
  • User
  • UserIdentifier

Architecture

 
This is the basic architecture which explains how data will pass from server to clients and from clients to Server 
 
As we know, in SignalR there are client and server concepts. It is a bi-directional data communication when they are connected to each other.
  1. The client sends data to Server
  2. The server sends data to the Client

Goals

 
When we are going to implement SignalR, then there are a set of goals which we need to achieve in this technology that are as follows:
  • Connection Management(Handshake)
  • Connect and Retry
  • Send/Receive message
  • Scales to handle increasing traffic.
  • Authentication
Based on our goals I have divided the flow into 2 sections and implemented it according to that:
  1. Client Management
  2. Server Management
Connection Management (Handshake)
 
To establish a connection, create a HubConnectionBuilder and call Build() method. The token is optional. If you want to use authentication, then pass the token and use the Authorize attribute in the Hub class. The hub URL, protocol, transport type, headers, and other options can be configured while building a connection. Configure any required options by inserting any of the HubConnectionBuilder methods into Build. It will start the connection with StartAsync method as shown in line number - 08.
  1. var token = “abccssfeofjef”;  
  2. var connection = new HubConnectionBuilder().WithUrl(endPoint, options => {  
  3.     options.AccessTokenProvider = () => Task.FromResult(token);  
  4. }).Build();  
  5. await connection.StartAsync();  
The endpoint is a host URL where our signalR server is a hosted token that we are providing for authentication.
 
Connect and Retry
 
Prior to 3.0, When connection got disconnected then the .NET client for SignalR doesn't automatically reconnect. You must write code that will reconnect your client manually.
 
Here in Use the Closed event to respond to a lost signalR connection. For example, you might want to automate reconnection.
  1. connection.Closed += async (error) =>  
  2. {  
  3.    // TODO Write your own logic  
  4. }  
In our case we have implemented Polly library for reconnect.
 
The Closed event requires a delegate that returns a Task, which allows async code to run without using async void. This is to satisfy the delegate signature in a Closed event handler that runs synchronously
 
Polly
 
One of the major differences between old and new .NET Core SignalR is that automatically reconnects are not supported in the older version. This means that you need explicitly write some code to open a new connection if you lost connection to the server.
 
I managed to write my own implementation that do automatic reconnects on this new version of .NET Core 2.2
 
The code bellow uses Polly for the automatic retry policy:
  1. private async Task Open() {  
  2.         var pauseBetweenFailures = TimeSpan.FromSeconds(20);  
  3.         var retryPolicy = Policy.Handle < Exception > ().WaitAndRetryForeverAsync(i => pauseBetweenFailures, (exception, timeSpan) => {  
  4.             _logger.LogDebug(exception.ToString());  
  5.         });  
  6.         await retryPolicy.ExecuteAsync(async () => {  
  7.             _logger.LogDebug("Retry Polly to connect to SignalR server");  
  8.             await TryOpen();  
  9.         });  
  10.         private async Task < bool > TryOpen() {  
  11.             _logger.LogDebug("Starting SignalR connection");  
  12.             await connection.StartAsync();  
  13.             _logger.LogDebug("SignalR connection established");  
  14.             return true;  
  15.         }  
Send/Receive message
 
We added Microsoft.AspNetCore.SignalR dll, then inherited Hub Class that are used to send a message at the client side.
 
InvokeAsync calls methods on the hub. Here we are Passing the hub method name and any arguments defined in the hub method to InvokeAsync. SignalR is asynchronous, so use async and await when making the calls.
 
The preceding code in connection.On runs when server-side code calls it using the Receive method.
  1. string messageObject = “hi this is test”;  
  2. await Clients.Client(Context.ConnectionId).Receive(messageObject);  
SendMessage
 
Use to send message at signalRServer side, in this method we are using send message object for client connection identity.
 
public async Task<IActionResult> Send (object message)
  
Define methods the hub calls using connection.This will catch server send notification if connection is succesfully created and hub connection is in connected state.
  1. hubConnection.On < string > ("Received", (responseMessage) => {  
  2.     response.Data = responseMessage.ToString();  
  3.     response.IsSuccess = true;  
  4.     response.Message = "";  
  5.     _logger.LogDebug(responseMessage);  
  6. });  
Server Management
 
Scales to handle increasing traffic.
 
An app that uses SignalR needs to keep track of all its connections, which creates problems for a server farm. Add a server, and it gets new connections that the other servers don't know about. For example, SignalR on each server in the following diagram is unaware of the connections on the other servers. When SignalR on one of the servers wants to send a message to all clients, the message only goes to the clients connected to that server.
 
Let's see an example:
 
Suppose we have multiple server (S1, S2, S3) and client have C1, C2
 
S1 connected with C1 and S2 connected with C2, S3 is free from any client.
 
But from the server side, when anyone tries to send data to C1 , then backplane comes in picture to internal transfer to its server then he(S1) will sent the real message. 
 
We have configured a few Redis properties
 
KeepAlive
 
Time (seconds) at which to send a message to help keep sockets alive (60-sec default)
 
ConnectRetry
 
The number of times to repeat connect attempts during initial Connect
 
ConfigCheckSeconds
 
Time (seconds) to check the configuration. This serves as a keep-alive for interactive sockets.
 
EndPoints
 
Hosted Url
 
SSL
 
Specifies that SSL encryption should be used
 
Authentication
 
By default, all methods in a hub can be called by an unauthenticated user. In order to require authentication, apply the Authorize attribute to the hub,
  1. [Authorize]  
  2. public class TestHub : Hub<ITestHub>  

Dependencies

 
S.N
Name
Version
1
Microsoft.AspNetCore.SignalR.Client
1.1.0
2
Microsoft.AspNetCore.SignalR
1.1.0
3
Polly
7.1.0
4
Microsoft.AspNetCore.SignalR.Redis
1.1.5
 
If you have any issues, please let me know. I am happy to look into this.
 
Hope this will help you to handle in dotnet core.
 
Thank you for taking your valuable time to read the full article.


Similar Articles