🚀 SignalR Basics: Real-Time Magic in ASP.NET
Imagine you’re at a party. Instead of everyone constantly asking “Any news? Any news?” the DJ just announces things when they happen. That’s SignalR!
🎯 What is SignalR?
SignalR is like a magical walkie-talkie for your web apps.
In normal websites, your browser has to keep asking the server: “Got anything new for me?” This is like a child in the backseat asking “Are we there yet?” every 5 seconds. Exhausting!
SignalR flips this around. The server can just tell your browser when something happens. No more asking. The server shouts, and everyone listening hears it instantly.
Why Does This Matter?
| Old Way (Polling) | SignalR Way (Real-Time) |
|---|---|
| Browser asks every few seconds | Server tells you immediately |
| Wastes resources | Super efficient |
| Delays of seconds | Instant updates |
| Like checking mailbox 100 times | Like getting a phone call |
Real-Life SignalR Examples
- 💬 Chat apps – Messages appear instantly
- 📊 Live dashboards – Numbers update in real-time
- 🎮 Multiplayer games – All players see the same thing
- 📢 Notifications – Alerts pop up the moment something happens
// This one line enables the magic!
builder.Services.AddSignalR();
🏠 SignalR Hubs: The Central Meeting Room
Think of a Hub as a clubhouse where everyone gathers.
A Hub is a special class on your server. It’s the “central station” where:
- Clients (browsers) connect
- Messages get sent and received
- The magic happens!
Creating Your First Hub
// ChatHub.cs
public class ChatHub : Hub
{
// Methods go here
// Clients can call these!
}
That’s it! You just created a meeting room. Now clients can join and talk.
Mapping Your Hub
// Program.cs
app.MapHub<ChatHub>("/chathub");
This says: “Hey, anyone who goes to /chathub can join our ChatHub meeting room!”
graph TD A["Your App"] -->|MapHub| B["ChatHub"] C["Browser 1"] -->|connects| B D["Browser 2"] -->|connects| B E["Browser 3"] -->|connects| B
📞 Hub Methods: The Conversations
Hub methods are like different phone extensions at a company.
You call a specific extension (method) to do a specific thing. Clients can call these methods from their browsers!
Example: A Simple Chat Method
public class ChatHub : Hub
{
public async Task SendMessage(
string user,
string message)
{
// Broadcast to ALL connected clients
await Clients.All.SendAsync(
"ReceiveMessage",
user,
message);
}
}
Breaking It Down
| Part | What It Does |
|---|---|
SendMessage |
The method clients can call |
user, message |
Data being sent |
Clients.All |
Send to everyone connected |
SendAsync |
The actual sending |
"ReceiveMessage" |
What clients listen for |
The Client Side (JavaScript)
// Calling the hub method
connection.invoke("SendMessage",
"Bob",
"Hello everyone!");
// Listening for responses
connection.on("ReceiveMessage",
(user, msg) => {
console.log(`${user}: ${msg}`);
});
🔌 Client Connections: Joining the Party
Every browser that connects gets a unique ID, like a wristband at a concert.
When someone connects, SignalR gives them a ConnectionId. This is their unique identity.
Connection Lifecycle
graph TD A["Client Opens Page"] -->|Handshake| B["Connection Established"] B --> C["ConnectionId Assigned"] C --> D["Client Can Send/Receive"] D -->|User leaves| E["OnDisconnectedAsync"]
Handling Connections in Your Hub
public class ChatHub : Hub
{
public override async Task OnConnectedAsync()
{
// Someone just joined!
string id = Context.ConnectionId;
await Clients.All.SendAsync(
"UserJoined", id);
await base.OnConnectedAsync();
}
public override async Task OnDisconnectedAsync(
Exception? ex)
{
// Someone left!
await Clients.All.SendAsync(
"UserLeft",
Context.ConnectionId);
await base.OnDisconnectedAsync(ex);
}
}
Key Properties You Get
| Property | What It Is |
|---|---|
Context.ConnectionId |
Unique ID for this client |
Context.User |
The authenticated user |
Context.Items |
Store data for this connection |
👥 Groups: Private Rooms Within the Party
Groups are like chat rooms inside the main hall.
Instead of shouting to everyone, you can whisper to just the people in a specific group.
Adding Someone to a Group
public async Task JoinRoom(string roomName)
{
// Add this connection to a group
await Groups.AddToGroupAsync(
Context.ConnectionId,
roomName);
// Tell the room someone joined
await Clients.Group(roomName).SendAsync(
"UserJoinedRoom",
Context.ConnectionId);
}
Sending to a Group
public async Task SendToRoom(
string room,
string message)
{
// Only people in this room hear it
await Clients.Group(room).SendAsync(
"RoomMessage",
message);
}
Leaving a Group
public async Task LeaveRoom(string roomName)
{
await Groups.RemoveFromGroupAsync(
Context.ConnectionId,
roomName);
}
graph TD H["ChatHub"] --> G1["Group: Sports"] H --> G2["Group: Music"] H --> G3["Group: Gaming"] G1 --> U1["User A"] G1 --> U2["User B"] G2 --> U3["User C"] G2 --> U4["User D"] G3 --> U1 G3 --> U4
Notice: Users can be in multiple groups!
🌊 Streaming: The River of Data
Streaming is like watching a live video instead of waiting for the whole thing to download.
Sometimes you don’t want to send all data at once. You want to send it piece by piece, like a video stream.
Server-to-Client Streaming
public async IAsyncEnumerable<int> Counter(
int count,
int delay)
{
for (var i = 0; i < count; i++)
{
yield return i;
await Task.Delay(delay);
}
}
Client Receiving the Stream
connection.stream("Counter", 10, 500)
.subscribe({
next: (item) => {
console.log("Got:", item);
},
complete: () => {
console.log("Stream done!");
},
error: (err) => {
console.error(err);
}
});
Client-to-Server Streaming
The client can also stream data TO the server!
public async Task UploadStream(
ChannelReader<string> stream)
{
while (await stream.WaitToReadAsync())
{
while (stream.TryRead(out var item))
{
// Process each item
Console.WriteLine(item);
}
}
}
When to Use Streaming?
| Use Case | Why Streaming? |
|---|---|
| Live charts | Data keeps flowing |
| File uploads | Send chunks |
| Progress updates | Piece by piece |
| Game positions | Constant updates |
🔄 Automatic Reconnection: Never Miss a Beat
Life happens. WiFi drops. Tunnels exist. SignalR handles it!
By default, if the connection drops, SignalR can automatically try to reconnect. Your users won’t even notice the blip!
Enabling Auto-Reconnect (Client)
const connection = new signalR
.HubConnectionBuilder()
.withUrl("/chathub")
.withAutomaticReconnect()
.build();
Custom Retry Delays
.withAutomaticReconnect([0, 2000, 10000, 30000])
// Retry immediately, then 2s, 10s, 30s
Handling Reconnection Events
connection.onreconnecting(error => {
console.log("Trying to reconnect...");
// Show "reconnecting" message
});
connection.onreconnected(connectionId => {
console.log("We're back! ID:", connectionId);
// Rejoin groups, refresh data
});
connection.onclose(error => {
console.log("Connection closed.");
// Show "disconnected" message
});
The Reconnection Flow
graph TD A["Connected"] -->|Connection Lost| B["Reconnecting"] B -->|Success| C["Reconnected"] B -->|Failed| D["Try Again"] D -->|Success| C D -->|Max Retries| E["Closed"] C --> A
Pro Tip: Rejoin Groups After Reconnect
When you reconnect, you get a NEW ConnectionId. That means you’re not in your old groups anymore!
connection.onreconnected(async () => {
// Rejoin your rooms
await connection.invoke("JoinRoom", "Gaming");
});
🎁 Putting It All Together
Here’s a complete mini-example:
Server (ChatHub.cs)
public class ChatHub : Hub
{
public async Task JoinRoom(string room)
{
await Groups.AddToGroupAsync(
Context.ConnectionId, room);
}
public async Task SendToRoom(
string room,
string user,
string msg)
{
await Clients.Group(room).SendAsync(
"NewMessage", user, msg);
}
}
Client (JavaScript)
const connection = new signalR
.HubConnectionBuilder()
.withUrl("/chathub")
.withAutomaticReconnect()
.build();
connection.on("NewMessage", (user, msg) => {
console.log(`${user}: ${msg}`);
});
await connection.start();
await connection.invoke("JoinRoom", "Lobby");
🌟 Key Takeaways
- SignalR = Real-time, two-way communication
- Hubs = Central meeting points for clients
- Hub Methods = Actions clients can call
- Connections = Each client has a unique ID
- Groups = Private rooms within the hub
- Streaming = Send data piece by piece
- Auto-Reconnect = Handle network hiccups gracefully
You’re no longer building websites. You’re building living, breathing, real-time experiences! 🚀
Now go build something amazing that updates instantly!
