ASP.NET Core SignalR: Complete Guide with Real-Time Examples
Introduction
In traditional web applications, the client usually sends a request to the server and waits for a response.
For example:
Angular Application
|
| HTTP Request
v
ASP.NET Core Web API
|
| HTTP Response
v
Angular Application
This works very well for normal CRUD operations.
But consider applications where information needs to appear immediately:
💬 Chat applications
🔔 Real-time notifications
📊 Live dashboards
🚚 Order/shipment tracking
🏦 Stock-price updates
🛒 E-commerce order status
🏭 IoT monitoring
🎮 Multiplayer applications
👥 Collaboration applications
📢 System alerts
Polling the server repeatedly is one possible solution, but it is inefficient.
This is where ASP.NET Core SignalR becomes useful.
1. What is SignalR?
SignalR is a real-time communication library for ASP.NET Core applications.
It allows the server to push data to connected clients without requiring the client to continuously request new data.
The communication can look like this:
ASP.NET Core Server
|
|
SignalR Hub
/ | \
/ | \
/ | \
Client A Client B Client C
When something happens on the server, the server can immediately notify connected clients.
For example:
Order Created
|
v
ASP.NET Core
|
v
SignalR Hub
|
+-----------> Customer 1
|
+-----------> Customer 2
|
+-----------> Admin Dashboard
No client polling is required.
2. Why Do We Need SignalR?
Suppose an Angular application displays an order status.
The order status changes on the server:
Order #1001
Status = Processing
A few seconds later:
Order #1001
Status = Shipped
Without SignalR, the Angular application might repeatedly call:
GET /api/orders/1001
For example:
Every 5 seconds
|
+---- GET /api/orders/1001
|
+---- GET /api/orders/1001
|
+---- GET /api/orders/1001
|
+---- GET /api/orders/1001
This is called polling.
It creates unnecessary HTTP requests.
With SignalR:
Server detects status change
|
v
SignalR Hub
|
v
Connected Client
|
v
UI updates immediately
3. SignalR Architecture
A simplified SignalR architecture looks like this:
Angular / React / JavaScript
|
|
SignalR Connection
|
v
ASP.NET Core
|
v
SignalR Hub
|
+----------+----------+
| |
Client A Client B
The major components are:
Client
SignalR Connection
Hub
Hub Methods
Server-to-Client Calls
Client-to-Server Calls
Groups
Connection Management
4. What is a SignalR Hub?
A Hub is the central communication point between clients and the server.
A Hub is similar to a controller in the sense that it exposes methods, but its purpose is real-time communication rather than traditional HTTP request/response processing.
Example:
public class NotificationHub : Hub
{
public async Task SendNotification(string message)
{
await Clients.All.SendAsync("ReceiveNotification", message);
}
}
Here:
Clients.All
means all connected clients.
And:
SendAsync("ReceiveNotification", message)
invokes a client-side method named:
ReceiveNotification
5. Creating a SignalR Project
Suppose we have an ASP.NET Core Web API application.
Install SignalR if necessary:
dotnet add package Microsoft.AspNetCore.SignalR
Depending on the ASP.NET Core version and project type, SignalR server functionality may already be included through the ASP.NET Core shared framework.
6. Create a SignalR Hub
Create a folder:
Hubs
Then create:
NotificationHub.cs
Code:
using Microsoft.AspNetCore.SignalR;
public class NotificationHub : Hub
{
public async Task SendNotification(string message)
{
await Clients.All.SendAsync(
"ReceiveNotification",
message);
}
}
This is our first SignalR Hub.
7. Configure SignalR in Program.cs
In ASP.NET Core:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddSignalR();
var app = builder.Build();
app.UseHttpsRedirection();
app.MapControllers();
app.MapHub<NotificationHub>("/notificationHub");
app.Run();
The important line is:
builder.Services.AddSignalR();
This registers SignalR.
The following line maps the Hub:
app.MapHub<NotificationHub>("/notificationHub");
The client can connect to:
/notificationHub
For example:
https://localhost:7001/notificationHub
8. Understanding SendAsync()
Consider:
await Clients.All.SendAsync(
"ReceiveNotification",
message);
There are three important pieces.
Clients.All
Sends the message to every connected client.
ReceiveNotification
This is the client-side method name.
message
This is the data being sent.
Conceptually:
Server
Clients.All.SendAsync(
"ReceiveNotification",
"Order Created"
)
|
v
Client A -> ReceiveNotification("Order Created")
Client B -> ReceiveNotification("Order Created")
Client C -> ReceiveNotification("Order Created")
9. JavaScript Client
Install the SignalR JavaScript client:
npm install @microsoft/signalr
Then:
import * as signalR from '@microsoft/signalr';
Create a connection:
const connection =
new signalR.HubConnectionBuilder()
.withUrl("https://localhost:7001/notificationHub")
.withAutomaticReconnect()
.build();
Start the connection:
connection.start()
.then(() => {
console.log("SignalR connected");
})
.catch(error => {
console.error(error);
});
10. Receiving Messages
The server sends:
await Clients.All.SendAsync(
"ReceiveNotification",
message);
The JavaScript client listens for:
connection.on(
"ReceiveNotification",
(message) => {
console.log(message);
});
Now the complete flow is:
ASP.NET Core
Clients.All.SendAsync(
"ReceiveNotification",
message
)
|
v
JavaScript
connection.on(
"ReceiveNotification",
message => {
console.log(message);
}
)
The method names must match:
ReceiveNotification
11. Complete Real-Time Notification Example
Let's build a realistic notification system.
Imagine an e-commerce application.
When an order is created:
Customer places order
|
v
Order API
|
v
Database
|
v
SignalR Hub
|
v
Customer/Admin Dashboard
The UI immediately displays:
🔔 New Order Created
Order Number: ORD-1001
Status: Processing
12. Notification Hub
using Microsoft.AspNetCore.SignalR;
public class NotificationHub : Hub
{
public async Task SendNotification(
string title,
string message)
{
await Clients.All.SendAsync(
"ReceiveNotification",
new
{
Title = title,
Message = message,
CreatedAt = DateTime.UtcNow
});
}
}
Now we can send an object rather than just a string.
13. Calling SignalR from an API Controller
Suppose we have:
[ApiController]
[Route("api/orders")]
public class OrdersController : ControllerBase
{
private readonly IHubContext<NotificationHub> _hubContext;
public OrdersController(
IHubContext<NotificationHub> hubContext)
{
_hubContext = hubContext;
}
[HttpPost]
public async Task<IActionResult> CreateOrder(
CreateOrderRequest request)
{
// Save order into database
var orderId = 1001;
await _hubContext.Clients.All.SendAsync(
"OrderCreated",
new
{
OrderId = orderId,
Status = "Processing"
});
return Ok(new
{
OrderId = orderId
});
}
}
This is an important real-world pattern.
We don't need to call a Hub method directly.
Instead, our Web API can inject:
IHubContext<NotificationHub>
and send messages to clients.
14. What is IHubContext?
IHubContext allows application code outside the Hub to communicate with connected clients.
For example:
Controller
Service
Background Worker
Azure Function
Message Consumer
|
v
IHubContext
|
v
SignalR Clients
Example:
private readonly IHubContext<NotificationHub> _hubContext;
Then:
await _hubContext.Clients.All.SendAsync(
"ReceiveNotification",
"New order created");
15. SignalR Client Types
SignalR provides several ways to target clients.
Clients.All
Send to everyone.
await Clients.All.SendAsync(
"ReceiveNotification",
message);
Clients.Caller
Send only to the client that made the request.
await Clients.Caller.SendAsync(
"ReceiveNotification",
message);
Clients.Others
Send to everyone except the caller.
await Clients.Others.SendAsync(
"ReceiveNotification",
message);
Clients.Client
Send to a specific connection.
await Clients.Client(connectionId)
.SendAsync(
"ReceiveNotification",
message);
16. SignalR Groups
Groups are extremely useful in real-world applications.
Imagine an enterprise application with:
Sales Team
Support Team
Managers
Administrators
We don't want every user to receive every notification.
Instead, we can create groups.
SignalR
+----------------------+
| Sales Group |
| User A |
| User B |
+----------------------+
+----------------------+
| Support Group |
| User C |
| User D |
+----------------------+
+----------------------+
| Manager Group |
| User E |
| User F |
+----------------------+
17. Joining a Group
public async Task JoinGroup(string groupName)
{
await Groups.AddToGroupAsync(
Context.ConnectionId,
groupName);
}
A client can call:
JoinGroup("Sales")
Now the client belongs to the Sales group.
18. Sending to a Group
await Clients.Group("Sales")
.SendAsync(
"ReceiveNotification",
"New sales order received");
Only clients in the Sales group receive the message.
This is very useful for:
Department notifications
Tenant-based applications
Project-based collaboration
Team dashboards
Chat rooms
Order-specific updates
19. Real-Time Order Tracking
Let's create a more realistic example.
Suppose an e-commerce order moves through:
Order Created
|
v
Processing
|
v
Packed
|
v
Shipped
|
v
Out for Delivery
|
v
Delivered
The server can notify the customer whenever the status changes.
Example:
await _hubContext.Clients
.Group($"order-{orderId}")
.SendAsync(
"OrderStatusChanged",
new
{
OrderId = orderId,
Status = "Shipped"
});
Only users watching that order receive the update.
20. Joining an Order Group
public async Task JoinOrderGroup(int orderId)
{
await Groups.AddToGroupAsync(
Context.ConnectionId,
$"order-{orderId}");
}
Client:
await connection.invoke(
"JoinOrderGroup",
orderId);
Then listen for:
connection.on(
"OrderStatusChanged",
(order) => {
console.log(
`Order ${order.orderId} status: ${order.status}`
);
}
);
21. Angular + SignalR
SignalR works very well with Angular.
Install:
npm install @microsoft/signalr
Create:
signalr.service.ts
Example:
import { Injectable } from '@angular/core';
import * as signalR from '@microsoft/signalr';
@Injectable({
providedIn: 'root'
})
export class SignalRService {
private connection!: signalR.HubConnection;
startConnection(): void {
this.connection =
new signalR.HubConnectionBuilder()
.withUrl(
'https://localhost:7001/notificationHub'
)
.withAutomaticReconnect()
.build();
this.connection
.start()
.then(() => {
console.log('SignalR connected');
})
.catch(error => {
console.error(error);
});
}
onNotification(
callback: (message: any) => void
): void {
this.connection.on(
'ReceiveNotification',
callback
);
}
}
22. Using SignalR Service in Angular Component
import { Component, OnInit } from '@angular/core';
import { SignalRService } from './signalr.service';
@Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html'
})
export class DashboardComponent
implements OnInit {
notification: any;
constructor(
private signalRService: SignalRService
) {}
ngOnInit(): void {
this.signalRService.startConnection();
this.signalRService.onNotification(
(message) => {
this.notification = message;
console.log(
'Notification received:',
message
);
}
);
}
}
23. SignalR Connection Lifecycle
A SignalR connection can have different states:
Disconnected
|
v
Connecting
|
v
Connected
|
v
Reconnecting
|
+----------+
| |
v v
Connected Disconnected
You can monitor connection events.
connection.onreconnecting(error => {
console.log('Connection lost. Reconnecting...');
});
connection.onreconnected(connectionId => {
console.log(
'Reconnected:',
connectionId
);
});
connection.onclose(error => {
console.log('SignalR connection closed');
});
24. Automatic Reconnection
SignalR supports automatic reconnect.
const connection =
new signalR.HubConnectionBuilder()
.withUrl('/notificationHub')
.withAutomaticReconnect()
.build();
You can also specify retry intervals:
.withAutomaticReconnect([
0,
2000,
5000,
10000
])
Meaning:
First retry -> Immediately
Second retry -> 2 seconds
Third retry -> 5 seconds
Fourth retry -> 10 seconds
25. WebSockets and SignalR
SignalR can use different transports.
The primary transport is:
WebSockets
Other supported transports can include:
Server-Sent Events
Long Polling
Conceptually:
SignalR
|
+---- WebSockets
|
+---- Server-Sent Events
|
+---- Long Polling
SignalR selects an appropriate transport based on the environment and client/server capabilities.
Therefore, developers normally don't need to implement WebSocket management manually.
26. SignalR vs WebSocket
A common interview question is:
"What is the difference between WebSockets and SignalR?"
WebSocket
WebSocket is a communication protocol that provides full-duplex communication between client and server.
SignalR
SignalR is a higher-level framework/library that provides real-time communication and can use WebSockets when available, while also supporting fallback transports.
| Feature | WebSocket | SignalR |
|---|---|---|
| Communication | Real-time | Real-time |
| Abstraction | Low-level | High-level |
| Automatic reconnect | Implement yourself | Supported |
| Groups | Implement yourself | Built-in |
| Client management | Manual | Built-in abstractions |
| ASP.NET Core integration | Manual | Excellent |
| Hub concept | No | Yes |
27. SignalR vs Polling
Polling
Client
|
| Request
v
Server
|
| Response
v
Client
Wait
Client
|
| Request
v
Server
This generates repeated requests.
SignalR
Client
|
| Establish connection
v
SignalR Server
|
| Connection remains available
|
| <--- Real-time message
|
| <--- Real-time message
|
| <--- Real-time message
This is much more suitable for real-time communication.
28. Authentication with SignalR
Enterprise applications usually need authentication.
For example:
Angular
|
| JWT
v
ASP.NET Core
|
v
SignalR Hub
Configure authentication:
builder.Services.AddAuthentication(
JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
// JWT configuration
});
Then:
builder.Services.AddAuthorization();
Hub:
[Authorize]
public class NotificationHub : Hub
{
}
Now only authenticated users can connect to the Hub.
29. Accessing the Current User
Inside a Hub:
var userId =
Context.User?.FindFirst("sub")?.Value;
You can also access:
Context.ConnectionId
and:
Context.User
This is useful for user-specific notifications.
30. User-Specific Notifications
Suppose User 1001 receives an order update.
We can send a message to that specific user:
await _hubContext.Clients
.User("1001")
.SendAsync(
"ReceiveNotification",
"Your order has been shipped.");
This is different from:
Clients.All
because only the specified user receives the notification.
31. Real-Time Enterprise Architecture
A typical enterprise architecture might look like:
Angular
|
|
API Management
|
+--------+--------+
| |
Web API SignalR
| |
| |
Microservices SignalR Hub
| |
| +------+------+
| | |
v v v
Database Client A Client B
|
v
Message Bus
For larger systems, events can flow through a message broker.
For example:
Order Service
|
v
Azure Service Bus / Kafka
|
v
Notification Service
|
v
SignalR
|
+------> Angular Client
|
+------> Admin Dashboard
This provides a scalable architecture.
32. SignalR with Background Services
SignalR is not limited to controllers.
A background service can also send notifications.
For example:
public class OrderMonitoringService
: BackgroundService
{
private readonly IHubContext<NotificationHub>
_hubContext;
public OrderMonitoringService(
IHubContext<NotificationHub> hubContext)
{
_hubContext = hubContext;
}
protected override async Task ExecuteAsync(
CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
await _hubContext.Clients.All.SendAsync(
"ReceiveNotification",
"Background process completed",
stoppingToken);
await Task.Delay(
TimeSpan.FromMinutes(1),
stoppingToken);
}
}
}
Register:
builder.Services.AddHostedService<OrderMonitoringService>();
33. SignalR in Microservices
In a microservices architecture, avoid making every microservice directly responsible for client connections.
A better architecture can be:
Angular
|
v
SignalR Service
^
|
Notification Service
^
|
Azure Service Bus / Kafka
^
|
+---------+---------+
| | |
Order Payment Shipping
Service Service Service
For example:
Order Service
|
| OrderCreated event
v
Azure Service Bus
|
v
Notification Service
|
v
SignalR
|
v
Angular
This creates better separation of responsibilities.
34. Scaling SignalR
This is very important for production systems.
Imagine:
100,000 users
connected to your application.
You may have multiple application instances:
Load Balancer
|
+--------------+--------------+
| | |
v v v
Server 1 Server 2 Server 3
| | |
SignalR SignalR SignalR
The problem is that clients can be connected to different servers.
For example:
Client A ---> Server 1
Client B ---> Server 2
If Server 1 sends a message locally, Server 2 may not automatically know about it.
For scaled-out SignalR deployments, you typically need a backplane or managed SignalR service depending on the architecture.
35. Azure SignalR Service
For Azure-based applications, Azure SignalR Service can handle SignalR connection scaling.
Architecture:
Angular Clients
/ | \
/ | \
v v v
Azure SignalR Service
|
|
v
ASP.NET Core API
|
v
Microservices
This can reduce the responsibility of managing large numbers of persistent client connections in your application servers.
For enterprise applications deployed on Azure, Azure SignalR Service is an important option to evaluate.
36. SignalR in AKS
If your application runs in AKS:
Azure
|
Application Gateway
|
Ingress
|
+-----------+-----------+
| | |
v v v
Pod 1 Pod 2 Pod 3
| | |
SignalR SignalR SignalR
Persistent connections introduce additional considerations when scaling.
For large-scale deployments, Azure SignalR Service can simplify the connection-management layer.
37. Real-World Use Case: Live Dashboard
Imagine an operations dashboard:
+---------------------------------------+
| REAL-TIME OPERATIONS DASHBOARD |
+---------------------------------------+
| Orders Today 12,542 |
| Successful Orders 11,934 |
| Failed Orders 108 |
| Pending Orders 500 |
+---------------------------------------+
Recent Events
-----------------------------------------
10:20:12 Order #1001 Created
10:20:15 Order #1002 Created
10:20:18 Order #1003 Shipped
10:20:22 Order #1004 Delivered
Instead of refreshing the browser:
Dashboard
|
| SignalR
v
ASP.NET Core
|
v
Real-time events
The dashboard updates automatically.
38. SignalR Error Handling
Always consider connection failures.
Server:
try
{
await Clients.All.SendAsync(
"ReceiveNotification",
message);
}
catch (Exception ex)
{
// Log exception
}
Client:
connection.start()
.catch(error => {
console.error(
'SignalR connection failed',
error
);
});
Use proper logging rather than silently ignoring errors.
39. Important SignalR Best Practices
1. Don't put business logic inside the Hub
Avoid:
public async Task CreateOrder()
{
// 500 lines of business logic
}
Prefer:
Hub
|
v
Application Service
|
v
Domain Service
|
v
Repository
2. Use strongly typed contracts
Instead of sending arbitrary objects everywhere, define DTOs.
public class OrderStatusNotification
{
public int OrderId { get; set; }
public string Status { get; set; } = string.Empty;
}
Then:
await _hubContext.Clients.All.SendAsync(
"OrderStatusChanged",
notification);
3. Use Groups
For large applications, groups are useful for:
Tenant
Department
Project
Order
Chat Room
Team
4. Enable Authentication
Don't expose sensitive real-time data to unauthenticated clients.
5. Handle Reconnection
Use:
.withAutomaticReconnect()
and monitor:
onreconnecting
onreconnected
onclose
6. Don't Send Excessive Data
Instead of:
Send entire database record
send only what the UI needs:
{
"orderId": 1001,
"status": "Shipped"
}
40. Complete SignalR Flow
The complete application flow can be represented as:
Angular Application
|
|
SignalR Connection
|
v
NotificationHub
|
^
|
IHubContext
^
|
Order Service
|
v
Database
With an event-driven architecture:
Angular
|
v
SignalR
^
|
Notification Service
^
|
Azure Service Bus / Kafka
^
|
Order Service
|
v
Database
41. SignalR Interview Questions
What is SignalR?
SignalR is a real-time communication library for ASP.NET Core applications that allows servers to push messages to connected clients.
What is a Hub?
A Hub is a high-level abstraction for communication between clients and the server.
What is IHubContext?
IHubContext allows application components outside a Hub to send messages to connected SignalR clients.
What is Clients.All?
It sends a message to all connected clients.
What is Clients.Caller?
It sends a message only to the client that initiated the Hub call.
What are SignalR Groups?
Groups allow connected clients to be logically grouped and targeted collectively.
Can SignalR work with Angular?
Yes. Microsoft provides the @microsoft/signalr JavaScript/TypeScript client.
Does SignalR always use WebSockets?
No. SignalR can use WebSockets when available and supports fallback transports.
How do you scale SignalR?
Depending on the deployment, options include a backplane or a managed service such as Azure SignalR Service.
Can SignalR be used with microservices?
Yes. A common pattern is to publish domain/application events through a message broker and have a notification component deliver relevant events to clients through SignalR.
42. SignalR vs REST API
| Feature | REST API | SignalR |
|---|---|---|
| Communication | Request/Response | Real-time |
| Server Push | No | Yes |
| Persistent Connection | Usually no | Yes |
| CRUD | Excellent | Not primary purpose |
| Notifications | Limited | Excellent |
| Chat | Not ideal | Excellent |
| Live Dashboard | Polling required | Excellent |
| Order Tracking | Polling required | Excellent |
| WebSockets | Not inherent | Supported |
SignalR does not replace REST APIs.
A modern application commonly uses both:
REST API
|
+---- CRUD operations
SignalR
|
+---- Real-time notifications
+---- Live status
+---- Events
43. Recommended Enterprise Architecture
For a large .NET + Angular application, a practical architecture could be:
Angular
|
+--------------+--------------+
| |
REST API SignalR
| |
v v
API Management Azure SignalR
| |
v |
ASP.NET Core APIs |
| |
+-----+------+ |
| | |
v v |
Orders Payments |
| | |
+-----+------+ |
| |
v |
Azure Service Bus ------------------+
|
v
Notification Service
This architecture provides:
Separation of responsibilities
Real-time client communication
Event-driven integration
Better scalability
Better support for microservices
Reduced polling
Better user experience
44. Conclusion
SignalR is one of the most useful technologies in the ASP.NET Core ecosystem when an application needs real-time communication.
It is especially useful for:
🔔 Notifications
💬 Chat
📊 Live dashboards
🚚 Order tracking
📈 Monitoring
🏭 IoT applications
👥 Collaboration
⚡ Real-time enterprise applications
The key concepts to remember are:
SignalR
|
+-- Hub
|
+-- Clients
|
+-- IHubContext
|
+-- Groups
|
+-- Connections
|
+-- Authentication
|
+-- Automatic Reconnection
|
+-- Scaling
|
+-- Azure SignalR Service
For a simple application:
Angular
|
v
SignalR Hub
|
v
ASP.NET Core
For an enterprise application:
Angular
|
+------ REST API
|
+------ SignalR
|
v
Azure SignalR Service
|
v
Notification Service
|
v
Azure Service Bus / Kafka
|
v
Microservices
The biggest advantage of SignalR is that the application doesn't have to continuously ask:
"Has anything changed?"
Instead, the server can tell the client immediately when something important happens.
That makes SignalR a strong choice for building responsive, event-driven, real-time .NET applications.

