Real-Time applications with SignalR

Aug 21 2023

Many thanks to the sponsors who make it possible for this newsletter to be free for readers.

 

Today's issue is sponsored by Milan Jovanovic.

 

Pragmatic Clean Architecture: Learn how to confidently ship well-architected production-ready apps using Clean Architecture. Milan used exact principles to build large-scale systems in the past 6 years. Join 700+ students here.

 

Use this promo code to get a 20% discount: PCAMW20

 

The first 20 people will get this discount, hurry up.

 
 

The Background

 
 

Ever been frustrated by having to constantly refresh a webpage to get the latest updates?

 

Or maybe you've wished your app could instantly show users new messages or notifications without them lifting a finger?

 

Yeah, we've all been there. That’s where SignalR comes to the rescue!

 

SignalR is like that cool tech wizard in the .NET, making real-time communication feel like a piece of cake. From chat apps, quick notifications, to live dashboard updates – SignalR is the secret sauce.

 

And the best part? It's all in C#, so it feels right at home for us .NET folks.

 

We need 4-5 steps to fully introduce SignalR in our code, so let's dive in.

 
 

SignalR Configuration

 
 

In order to use SignalR, first you need to install it as a library from NuGet.

 

You need to install the following package:

Install-Package Microsoft.AspNetCore.SignalR.Client

 

The first thing to configure is the SignalR Hub. The hub is the high-level pipeline able to call the client code, sending messages containing the name and parameters of the requested method.

 

You need to create a class which will inherit the base "Hub" class from SignalR package:

public class NotificationsHub : Hub
{
    public async Task SendNotification(string message)
    {
        await Clients.All.SendAsync("ReceiveNotificaiton", message);
    }
}

 

And as the last part, like everything else, it is necessary to register SignalR through Dependency Injection in the Program.cs class.

 

It's quite straightforward - add the SignalR service and map the Hub used:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddSignalR();

var app = builder.Build();

app.MapHub<NotificationsHub>("notifications-hub");

app.Run();

 
 

Configure Client side

 
 

On the client side you can use anything, in this case, I use javascript for easier display and understanding of what is actually happening.

 

First I will create the most common HTML components:

 

1. Input field for the message I am sending
2. The send button
3. List of sent/received messages

<input type="text" id="messageBox" placeholder="Your message" />
<button id="sendButton">Send</button>

<ul id="messageList"></ul>

 

I will also upload the .js script for Signalr so that I can use it on the client:

<script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/6.0.1/signalr.js"></script>

 

When the page is loaded, the first thing that needs to happen is to establish a connection to the SignalR Hub.

 

For that I will use the signalR.HubConnectionBuilder() call with the Hub URL we created on the .NET side.

 

Note: "notification-hub" must match on both sides - in javascript and in .NET configuration (Program.cs).

<script>
    $(function() {
        const connection = new signalR.HubConnectionBuilder()
            .withUrl("/notifications-hub")
            .configureLogging(signalR.LogLevel.Information)
            .build();

        async function start() {
            try {
                await connection.start();
                console.log("SignalR Connected.");
                await connection.invoke("SendNotification", "Initial Notification");
            } catch (err) {
                console.log(err);
                setTimeout(start, 5000);
            }
        };

        connection.onclose(async () => {
            await start();
        });

        start();
    });
</script>

 

After that, when the connection exists, I will start the connection. I will put everything in the try/catch block if there are any errors. Now we have a complete connection connected.

 
 

Send/Receive messages

 
 

Let's send message to Hub:

 

I want to enter a message in the input and by clicking the "Send" button, a message is sent to NotificationHub on the .NET page, which I will immediately receive as a notification, shown in the list of received notifications.

Testing SignalR  

To achieve this, on the click event of the button, I grab the message from the input and call connection.invoke("SendNotification", message), where:

 

- the first parameter is the name of the method in NotificationHub,
- the message is the parameter, actually, the message I'm sending.

  $("#sendButton").on('click', function() {
            var message = $("#messageBox").val();
            connection.invoke("SendNotification", message);
        });

 

Let's send message from Hub to Client in real-time:

 

One client sent a message to the Hub, we process that message in the Hub and in Real-Time we send a notification about the message we received to all connected clients.

Notifications Hub Debugging  

"ReceiveNotification" is an event on the client side that will accept the notification and process the data we send (it will put them in a list).

  connection.on("ReceiveNotification", (message) => {
            const li = document.createElement("li");
            li.textContent = `${message}`;
            document.getElementById("messageList").appendChild(li);
        });

 

With this, we have achieved complete communication in real time between the Hub and clients connecting to the Hub.

 
 

Wrapping up

 
 

So in short, when we need communication (sending notifications, chat applications, real-time dashboard) in real time, SignalR proved to be a great choice.

 

It is necessary to do the following things in order to establish the connection:

 

- Configure SignalR on the .NET side - Hub
- Configure on the client side - connect to the Hub
- Implement methods/events/handles for sending and receiving messages

 

I didn't mention:

 

In the example, I showed sending messages to all connected users, so the message also reached me.
Here it is possible to configure and send messages to certain users or to one user, for example:

 

Clients.User(userId).ReceiveNotification(content);

 

In addition to accessing the client list, SignalR Hub also supports access to:

 

- Groups - adding and removing connections from groups
- Context - accessing information about the hub caller connection

 

I encourage you to look at the complete source code that I leave here and write to me if you have any questions.

 

Here is the source code on GitHub.

 

That's all from me today.

Join 10,950+ subscribers to improve your .NET Knowledge.

There are 3 ways I can help you:

Design Patterns Simplified ebook

Go-to resource for understanding the core concepts of design patterns without the overwhelming complexity. In this concise and affordable ebook, I've distilled the essence of design patterns into an easy-to-digest format. It is a Beginner level. Check out it here.


Sponsorship

Promote yourself to 10,950+ subscribers by sponsoring this newsletter.


Join .NET Pro Weekly Newsletter

Every Monday morning, I share 1 actionable tip on C#, .NET & Arcitecture topic, that you can use right away.


Subscribe to
.NET Pro Weekly

Subscribe to the .NET Pro Weekly and be among the 10,950+ subscribers gaining practical tips and resources to enhance your .NET expertise.