SignalR Made Simple: Unlocking Real-Time Power in Your Application

Table of contents

🛠 What We’re Building
In this guide, we’ll walk through step by step how to implement a real-time team chat app using ASP.NET Core SignalR on the backend and Angular on the frontend.
By the end, you’ll have a working setup where users can join groups, send messages, and receive real-time updates.
📦 Step 1: Set Up the SignalR Hub
We start by creating a Hub in ASP.NET Core. This is the core piece that manages the real-time connections.
// File: Hubs/TeamChatHub.cs
using Microsoft.AspNetCore.SignalR;
using System.Threading.Tasks;
public class TeamChatHub : Hub
{
// Join a group (e.g., Dev, QA, Sales)
public async Task JoinGroup(string groupName)
{
await Groups.AddToGroupAsync(Context.ConnectionId, groupName);
await Clients.Group(groupName).SendAsync("ReceiveMessage", "System", $"{Context.ConnectionId} joined {groupName}");
}
// Leave a group
public async Task LeaveGroup(string groupName)
{
await Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName);
await Clients.Group(groupName).SendAsync("ReceiveMessage", "System", $"{Context.ConnectionId} left {groupName}");
}
// Send message to group
public async Task SendMessageToGroup(string groupName, string user, string message)
{
await Clients.Group(groupName).SendAsync("ReceiveMessage", user, message);
}
}
✅ What’s happening?
Clients can join or leave named groups.
Messages sent to a group are broadcasted to all group members.
Explanation:
JoinGroup()
uses:await Groups.AddToGroupAsync(Context.ConnectionId, groupName);
This adds the client’s connection (
Context.ConnectionId
) to a named group like Dev, QA, or Sales.LeaveGroup()
uses:await Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName);
This removes the client from the group.
SendMessageToGroup()
:
Sends messages only to clients inside the specified group.💡 Tip:
Here, you can also track which user joined by saving theirConnectionId
, username, and group in your database.
When removing, you can clear or update the session record in your database to show the user has left or gone offline.This helps you show online users or manage who’s active.
✅ Why?
Useful for showing online users.
Helps with managing group permissions or session timeouts.
🚀 Step 2: Create the SignalR Controller (Optional API)
We add a controller to send messages via HTTP API (for scenarios where backend services need to push updates).
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
namespace PracticeWebApplication.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class SignalRController : ControllerBase
{
private readonly IHubContext<TeamChatHub> _hubContext;
public SignalRController(IHubContext<TeamChatHub> hubContext)
{
_hubContext = hubContext;
}
[HttpPost("sendMessage")]
public async Task<IActionResult> SendMessageToGroup([FromQuery] string groupName, [FromBody] MessageDto message)
{
await _hubContext.Clients.Group(groupName).SendAsync("ReceiveMessage", message.User, message.Content);
return Ok("Message sent");
}
}
public class MessageDto
{
public string User { get; set; }
public string Content { get; set; }
}
}
✅ What’s happening?
- Exposes an API endpoint
POST /api/signalr/sendMessage
to push messages to a group.
🔧 Step 3: Configure ASP.NET Core
In your Startup.cs
(or Program.cs
in .NET 6+), make sure to map the SignalR hub.
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapHub<TeamChatHub>("/teamChatHub");
});
✅ Tip: Don’t forget to enable CORS if your frontend is on a different origin.
🌐 Step 4: Set Up Angular Frontend
Let’s switch to the Angular side and create the UI and SignalR connection.
🔌 Install SignalR Client
Run:
npm install @microsoft/signalr
📄 Angular Component HTML (UI)
<h2>Team Chat</h2>
<select #groupSelect>
<option value="Dev">Dev</option>
<option value="QA">QA</option>
<option value="Sales">Sales</option>
</select>
<button (click)="joinGroup(groupSelect.value)" [disabled]="!connected">Join Group</button>
<button (click)="leaveGroup()">Leave Group</button>
<br /><br />
<input type="text" [(ngModel)]="userName" placeholder="Your Name" />
<input type="text" [(ngModel)]="messageText" placeholder="Enter message" />
<button (click)="sendMessage()" [disabled]="!connected || !currentGroup">Send</button>
<ul>
<li *ngFor="let msg of messages">{{ msg }}</li>
</ul>
✅ What’s happening?
Dropdown to pick a group.
Inputs for username and message.
Message list displaying chat history.
📄 Angular Component TypeScript (Logic)
import { Component, OnInit } from '@angular/core';
import * as signalR from '@microsoft/signalr';
@Component({
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrls: ['app.component.css']
})
export class AppComponent implements OnInit {
connection!: signalR.HubConnection;
currentGroup: string = '';
userName: string = '';
messageText: string = '';
messages: string[] = [];
connected: boolean = false;
ngOnInit(): void {
this.connection = new signalR.HubConnectionBuilder()
.withUrl('https://localhost:44311/teamChatHub')
.build();
this.connection.on('ReceiveMessage', (user: string, message: string) => {
this.messages.push(`${user}: ${message}`);
});
this.connection
.start()
.then(() => {
console.log('Connected to SignalR');
this.connected = true;
})
.catch(err => console.error('Connection error:', err.toString()));
}
joinGroup(group: string): void {
this.currentGroup = group;
this.connection.invoke('JoinGroup', group)
.catch(err => console.error('JoinGroup error:', err.toString()));
}
leaveGroup(): void {
if (this.currentGroup) {
this.connection.invoke('LeaveGroup', this.currentGroup)
.catch(err => console.error('LeaveGroup error:', err.toString()));
this.currentGroup = '';
}
}
sendMessage(): void {
if (this.currentGroup && this.userName && this.messageText) {
this.connection.invoke('SendMessageToGroup', this.currentGroup, this.userName, this.messageText)
.catch(err => console.error('SendMessage error:', err.toString()));
this.messageText = ''; // Clear input after send
}
}
}
✅ What’s happening?
Establishes a SignalR connection on load.
Handles joining/leaving groups.
Listens for
ReceiveMessage
and updates the message list.
✅ Final Checklist
Backend SignalR Hub ready
Angular frontend wired up
Group join/leave + real-time messaging working
Optional API endpoint for backend push
Check your backend port — match it in Angular’s
withUrl()
.Enable CORS if frontend and backend run on different origins.
Test locally before deploying.
🎉 Conclusion
Congrats! You now have a real-time team chat app running with SignalR.
This pattern can be expanded to:
Live dashboards
Notifications
Collaborative tools
Multiplayer games
If you found this guide helpful, leave a like ❤️ or share it!
Subscribe to my newsletter
Read articles from Pranali Kulkarni directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
