Quick answer: SignalR is Microsoft’s open source library for adding real-time communication to ASP.NET Core apps. It lets the server push updates to connected browsers and apps the moment something happens, instead of clients polling for changes. SignalR picks the best available transport, preferring WebSockets and falling back to Server-Sent Events or long polling. You define a hub on the server, connect to it from a JavaScript or .NET client, and call methods in both directions. It is a good fit for dashboards, notifications, chat, live status updates and collaborative tools.
What problem SignalR solves
The web was built around request and response. The browser asks, the server answers. That works for most pages, but it falls short when the server knows something the client needs right away: a new order on a dashboard, a message in a support chat, or a job that has just finished processing.
The traditional workaround was polling. The browser asks “anything new?” every few seconds. Polling is simple but wasteful. Most requests return nothing, and updates still arrive late.
WebSockets solve this with a persistent two-way connection. Working with raw WebSockets, though, means handling connection management, reconnection, message formats and fallbacks yourself. SignalR handles that work so you can focus on the feature.
Where SignalR fits
Typical uses include:
- Live dashboards. Sales, orders, sensor readings or system health updating without a refresh.
- Notifications. Telling a user their report is ready or a colleague has commented.
- Chat and support. Customer support widgets and internal messaging.
- Progress updates. Showing progress for long-running background jobs.
- Collaboration. Several users editing or viewing the same record and seeing each other’s changes.
- Auctions, bookings and inventory. Showing availability that changes by the second.
If your app only needs updates once an hour, SignalR is overkill. If users expect to see changes as they happen, it is worth a look.
How SignalR works
Hubs
A hub is a class on the server that clients connect to. The hub exposes methods that clients can call, and the server can call methods on connected clients. Under the hood SignalR handles serialization, so you work with normal method calls and objects.
Transports
SignalR supports three transports and negotiates the best one each client can use:
- WebSockets, the preferred option, with a full two-way connection.
- Server-Sent Events, a one-way stream from server to client, with client messages sent over regular requests.
- Long polling, where the client holds a request open until the server has something to send.
Most modern browsers and servers support WebSockets. The fallbacks matter for corporate networks and proxies that block them.
Protocols
Messages are sent as JSON by default. SignalR also supports MessagePack, a binary format that produces smaller messages and is useful for high-volume scenarios.
A minimal setup in ASP.NET Core
SignalR is part of ASP.NET Core, so there is nothing extra to install on the server. In ASP.NET Core 3.1 and .NET 5 you register it in Startup.
Create a hub:
using Microsoft.AspNetCore.SignalR;
using System.Threading.Tasks;
public class NotificationHub : Hub
{
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
}
Register services and map the hub in Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddSignalR();
}
public void Configure(IApplicationBuilder app)
{
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapHub<NotificationHub>("/hubs/notifications");
});
}
Connect from the browser with the JavaScript client from the @microsoft/signalr npm package:
const connection = new signalR.HubConnectionBuilder()
.withUrl("/hubs/notifications")
.withAutomaticReconnect()
.build();
connection.on("ReceiveMessage", (user, message) => {
console.log(user + ": " + message);
});
connection.start().catch(err => console.error(err));
The withAutomaticReconnect option, added in ASP.NET Core 3.0, tells the client to try reconnecting after a dropped connection instead of giving up.
Sending messages from outside the hub
Real apps rarely send messages only in response to other client calls. Usually something happens elsewhere, such as a controller saving an order or a background service finishing a job. Inject IHubContext to send from anywhere:
public class OrdersController : ControllerBase
{
private readonly IHubContext<NotificationHub> _hub;
public OrdersController(IHubContext<NotificationHub> hub)
{
_hub = hub;
}
[HttpPost]
public async Task<IActionResult> Create(Order order)
{
// save the order
await _hub.Clients.Group("sales").SendAsync("NewOrder", order.Id);
return Ok();
}
}
This pattern is common when adding real-time updates to an existing ASP.NET Core Web API.
Targeting the right clients
Sending to everyone is rarely what you want. SignalR gives you several ways to target messages:
- Clients.All sends to every connected client.
- Clients.Caller sends back to the client that made the call.
- Clients.User(userId) sends to every connection belonging to an authenticated user, which covers multiple tabs and devices.
- Clients.Group(name) sends to a named group. Add connections with Groups.AddToGroupAsync.
Groups are useful for rooms, teams, tenants or records. A user viewing order 1042 can join the group “order-1042” and receive updates only for that order. Group membership is not persisted, so rejoin groups when a client reconnects.
Strongly typed hubs
Calling client methods by string name works but is easy to get wrong. A strongly typed hub uses an interface instead:
public interface INotificationClient
{
Task ReceiveMessage(string user, string message);
}
public class NotificationHub : Hub<INotificationClient>
{
public Task SendMessage(string user, string message)
=> Clients.All.ReceiveMessage(user, message);
}
The compiler now catches typos in method names.
Authentication and authorization
Hubs work with standard ASP.NET Core authentication. Add the [Authorize] attribute to a hub or to individual methods to require a signed-in user.
With cookie authentication, the browser sends the cookie automatically. With JWT bearer tokens, browsers cannot set headers on WebSocket requests, so the JavaScript client sends the token in the query string. Configure the JWT handler to read it from there for hub paths only. Keep tokens short-lived, and make sure query strings are not written to your logs.
Scaling SignalR
A single server can hold many connections, but real-time apps need extra thought when you run more than one server.
The scale-out problem
Each connection lives on one server. If a message is sent from server A, clients connected to server B will not receive it unless the servers share messages.
Options
- Redis backplane. Each server publishes messages to Redis, which forwards them to the others. Good for a few servers in your own hosting.
- Azure SignalR Service. A managed service that holds the client connections for you. Your app servers talk to the service, and it handles fan-out and connection limits. This is often the easiest route on Azure, and pairs well with Azure Functions for serverless setups.
Sticky sessions
Unless every client uses WebSockets with negotiation skipped, or you use Azure SignalR Service, the load balancer needs sticky sessions so a client’s requests reach the same server.
Practical tips
- Send small messages. Send an ID and let the client fetch details if it needs them.
- Handle reconnection in the UI. Show a small “reconnecting” state so users know updates may be delayed.
- Do not trust client calls. Validate inputs and check permissions inside hub methods.
- Log connection counts and errors so you can spot problems early.
- Load test before launch if you expect many concurrent users.
SignalR and Blazor
If you are building with Blazor, note that Blazor Server already uses a SignalR connection under the hood to send UI updates between browser and server. You can still add your own hubs for app-specific messages.
Moving from ASP.NET SignalR
The older ASP.NET SignalR for .NET Framework is not compatible with ASP.NET Core SignalR. Clients and servers must use the same version. Teams moving from .NET Framework to .NET Core need to update both sides, along with any jQuery-based client code.
Questions developers ask
Is SignalR only for chat apps?
No. Chat is the classic demo, but dashboards, notifications and progress updates are far more common in business apps.
Can mobile apps connect to SignalR?
Yes. The .NET client works in Xamarin apps, and other platforms can use the available clients or the JavaScript client in web views.
Does SignalR guarantee message delivery?
No. If a client is disconnected, messages sent during that time are lost. For important data, store it and let clients catch up after reconnecting.
Wrapping up
SignalR is one of the simplest ways to add real-time features to an ASP.NET Core app. Start with a hub, a small set of messages and the JavaScript client, use groups and user targeting to send updates only where they belong, and plan for scale-out before traffic grows.
If you need real-time features added to an existing .NET app, take a look at our custom development services.