If you are using ASP.NET Core for web application development, you should get yourself familiar with SignalR library. And once you have, you will be surprised how you used to manage without it.
If you open any modern day web application, from a social media web page to your in-browser email client, there will be a feature that everyone these days takes for granted – the ability to refresh any arbitrary parts of the web page in real time without having to reload the entire page. And this is just the most basic things you can do with SignalR.
Although you don’t necessarily need SignalR to achieve an asynchronous real-time data transfer between clients and the servers, SignalR is by far the best way of implementing it in ASP.NET. Let’s find out why is it so.
What SignalR does
SignalR is a library that was published by Microsoft as one of the modules of ASP.NET Core since version 2.1. Prior to this, it has been available in the .NET Framework-based ASP.NET classic. The more recent .NET Core version is a complete rewrite of it, rather just a mere port of the original code.
The key purpose of SignalR is to enable two-way asynchronous real-time communication between the client and the server. So, instead of a classic request-response model where clients have to send a request to the server to get some data returned from it in a response, SignalR just enables a persistent connection, which enables the data to travel both way at any point in time.
The best way of doing so is to use WebSocket protocol, which SignalR uses under the hood by default. Under some circumstances, WebSocket cannot be used. This, however, isn’t an issue for SignalR. It will just use a different communication mechanism instead.
Modern ASP.NET Core SignalR version uses server-sent events if WebSocket cannot be used for any reason. If server-sent events aren’t available either, SignalR can fall back to long polling, which is not as efficient, but is available everywhere.
ASP.NET classic version of SignalR also has forever frame as one of its communication mechanisms. However, as this technology has limited availability and is pretty much obsolete, it hasn’t been made available on the ASP.NET Core version.
As well as using these transport mechanisms in a fallback hierarchy, SignalR client can explicitly choose which one to use. So, if you, for whatever reason, need to use long polling even when WebSocket is enabled, you can do so.
ASP.NET Core version is the one we will focus on in this article; although most of the benefits apply equally well to the ASP.NET classic version. So, let’s jump to the reasons why SignalR is way better than any alternatives you may encounter.
All complexity is abstracted away
If you want to create your own implementation of a WebSocket server, good luck. Of course, it is doable, but there are way too many things to take care of.
For example, you will probably have to split your messages into streams of bytes of the equal size and send them in sequence. So, your code will probably look something like this:
Not very readable, is it?
So, already there are some decision to make. What is the size of each byte array? And how do you clean up unused elements from the last byte array to reconstruct the message into its original form? This is why both your client and your server will have to have something like this:
And what do you do if one of the message chunk fails to get transmitted? Do you start over, or do you just retry for those arrays that haven’t been transmitted yet?
And what about a scenario where you can’t even use WebSocket? In this case, you will have to write quite a lot of extra code to handle other transport mechanisms.
With SignalR, none of these will matter. The code is so simple that it looks almost like you can directly call methods on the server from a client and vice versa.
For example, this is a method that you can have on the server:
This is how you can call it from a web page:
This is how you can call it from a non-browser client:
Yes, SignalR works with any types of client and not necessarily web pages. We will cover more of this later.
This is an example of a client method that the above server method calls:
And this is the same method on a non-browser client:
Of course, remote method calling is not what actually happens under the hood. But all complex implementation details have been abstracted away, so this is not something you, as a developer, will have to worry about.
Likewise, the code will be exactly the same regardless of which transport mechanisms you use. Of course, your WebSocket network traffic will look different from what will happen if you’ll use long polling. But the code will still look the same regardless.
No more need for AJAX
Back in the days, AJAX was a standard way of making partial updates to a web page by asynchronously retrieving some data chunks from the server. This was especially popular when jQuery was used everywhere.
AJAX was completely fine when all you needed was to retrieve data from the server when some user-initiated action happened on the web page. But what if you needed to retrieve new data as soon as it becomes available?
With AJAX, you would have to implement some sort of logic that queries the server at regular intervals. This would make real-time applications, such as chat, fairly inefficient and not necessarily fully synchronized in time.
With SignalR, you won’t have to do any of this. Your client will automatically receive the update as soon as the data is available. In a chat scenario, which is often used as a SignalR example, all participants will receive the message as soon as someone posts it.
With SignalR, however, the persistent connection is just kept open, so, except for an occasional heartbeat data transfer that is small in size, it’s pretty much only the data that gets transmitted with very little in terms of extra payload.
Works with any types of client
Browser-based clients are a common use case for SignalR. However, in real world, not all the clients are browser-based. For example, you may have some IoT devices that communicate with the centralized hub on the server.
For instance, this online course provides an example of how to use a pure WebSocket client with your SignalR hub.
As these transport mechanisms can be implemented in any programming language on any platform, your SignalR client can be written in any programming language on any platform.
Can be scaled out very easily
SignalR has a number of in-built ways of scaling your application out. This would be extremely difficult if you would have to do it on your own for applications with persistent real-time connection. For example, if you want to send a message from a particular client to all clients in a particular group, how would you identify all required clients, if they are connected to different nodes in a load-balanced cluster?
With SignalR, there is Redis-based backplane mechanism, which allow all nodes in the cluster to notify each other in real time. Therefore your application code will be exactly the same, regardless of whether you are running a single instance of it or many instances. They will still act like a single application.
Another way of scaling out your SignalR application is to use Azure SignalR Service. In this case, you will just delegate all load balancing to Azure cloud, which will automatically scale it based on the demand. In this case, you will just have to pay more if people use it more.
Used in other parts of ASP.NET Core
The final feature of SignalR that I would like to cover is that it is integrated into other parts of ASP.NET Core, so it will be useful to know, even if you don’t intend to use it directly. For example, it is used to facilitate communication between the client and the server in server-side Blazor.
As well as this, it is used inside some premium Microsoft products. Visual Studio is one of them.
If you, as an ASP.NET developer, will ever need to establish an asynchronous real-time two-way communication between the client and the server (which you definitely will), SignalR is the library you will need to get yourself familiar with.
And it will do so in a very convenient way by abstracting away all the complex implementation details, so your client and the server will look like they are just calling each other’s methods directly.
SignalR makes AJAX obsolete and improves your network bandwidth usage in the process. And you can write your client code in any programming language on any platform.
SignalR can be scaled out extremely easily. You can do so either in your own code by sharing a backplane between the application instances or by utilizing Azure SignalR Service.
Finally, SignalR is used extensively by Microsoft itself, both in its programming frameworks and its premium products. So, if it’s good for Microsoft, it is certainly good for you.
P.S. if you want to learn more about SignalR, you can check out my book SignalR on .NET 6 – the complete guide.