DEV Community

Cover image for πŸ“‘ SignalR: Real-Time Communication in .NET Core
Saurabh Khade
Saurabh Khade

Posted on

2 1

πŸ“‘ SignalR: Real-Time Communication in .NET Core

First of all, let's understand SignalR.

πŸš€ SignalR is an open-source library built for .NET, designed to facilitate real-time communication in applications. Unlike the traditional request-response model, where the client sends a request and waits for a server response, SignalR enables two-way communication via a persistent connection.

πŸ”„ Think of WhatsApp! πŸ’¬ Whenever someone sends you a message, it instantly appears on your screen (server pushing data to the client). Similarly, when you send a message, it reaches the recipient immediately (client sending data to the server).

πŸ“– Further Reading:

Now, let’s implement SignalR in .NET Core by building a simple backend for a chat application. πŸ’»


πŸ› οΈ Installing the SignalR NuGet Package

Install the latest SignalR package from NuGet using the following command:

dotnet add package Microsoft.AspNetCore.SignalR
Enter fullscreen mode Exit fullscreen mode

πŸ“Œ Alternatively, you can install it via the NuGet Package Manager UI.

Nuget package manager window


πŸ“ Creating a SignalR Hub

πŸ”— The Hub is the central component of SignalR that enables real-time communication. It allows clients and servers to call each other’s methods. Let's create a basic ChatHub:

using Microsoft.AspNetCore.SignalR;

namespace MySignalRProject.Hubs
{
    // Create a hub class by inheriting SignalR Hub
    public class ChatHub : Hub
    {
        // A server event triggered by the client
        public async Task SendMessage(string message)
        {
            // Broadcast the message to all connected clients
            await Clients.All.SendAsync("ReceiveMessage", message);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

πŸ” How does it work?

  • Clients call SendMessage(message), sending a message to the server.
  • The server then triggers ReceiveMessage(message), sending it to all connected clients.

❓ Problem: Sending a message to everyone isn't always ideal.
βœ… Solution: We can use Groups to restrict message delivery.


πŸ‘₯ Implementing Groups in SignalR

πŸ”Ή Groups allow clients to join specific chat rooms.
πŸ”Ή Only users in a group will receive messages sent to that group.

Here’s how to implement it:

using Microsoft.AspNetCore.SignalR;

namespace MySignalRProject.Hubs
{
    public class ChatHub : Hub
    {
        // Join a specific group
        public async Task Connect(string groupId)
        {
            await Groups.AddToGroupAsync(Context.ConnectionId, groupId);
        }

        // Leave a group
        public async Task Disconnect(string groupId)
        {
            await Groups.RemoveFromGroupAsync(Context.ConnectionId, groupId);
        }

        // Send a message to a specific group
        public async Task SendMessage(string groupId, string message)
        {
            await Clients.Group(groupId).SendAsync("ReceiveMessage", message);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

βœ… Now, only members of a specific group will receive messages sent to that group.


🌍 Exposing the Hub via API

πŸ› οΈ Register SignalR services in Startup.cs or Program.cs:

services.AddSignalR();
Enter fullscreen mode Exit fullscreen mode

πŸ”— Expose ChatHub publicly at /chathub:

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
    endpoints.MapHealthChecks("/health");
    endpoints.MapHub<ChatHub>("/chatHub"); // Exposing SignalR Hub
});
Enter fullscreen mode Exit fullscreen mode

πŸŽ‰ Once your API starts, the real-time chat hub will be accessible at /chathub!


⚑ Making SignalR Type-Safe

πŸ›‘ Potential Issue:

await Clients.Group(groupId).SendAsync("ReceiveMessage", message);
Enter fullscreen mode Exit fullscreen mode

If a developer mistypes "ReceiveMessage" as "ReceivedMessage" or "receiveMessage", debugging the issue can be time-consuming.

βœ… Solution: Use Strongly Typed Hubs to enforce correct method names.

1️⃣ Define Client Events in an Interface

namespace MySignalRProject.Hubs.Interfaces
{
    public interface IClientChatHub
    {
        Task ReceiveMessage(string message);
        Task ReceiveReaction(int userId, string reaction);
    }
}
Enter fullscreen mode Exit fullscreen mode

2️⃣ Implement a Strongly Typed Hub

using Microsoft.AspNetCore.SignalR;
using MySignalRProject.Hubs.Interfaces;

namespace MySignalRProject.Hubs
{
    public class ChatHub : Hub<IClientChatHub>
    {
        public async Task Connect(string groupId)
        {
            await Groups.AddToGroupAsync(Context.ConnectionId, groupId);
        }

        public async Task Disconnect(string groupId)
        {
            await Groups.RemoveFromGroupAsync(Context.ConnectionId, groupId);
        }

        public async Task SendMessage(string groupId, string message)
        {
            // No more typos! Method calls are now type-checked.
            await Clients.Group(groupId).ReceiveMessage(message);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

πŸ”Ž Comparison: Strongly Typed vs. Traditional Approach

❌ Group.SendAsync("EventName") βœ… Group.EventName
Typos can break functionality ⚠️ No typo worries πŸš€
No restrictions on event calls Strict event control βœ…
No parameter validation Parameter types are enforced πŸ› οΈ

βœ… Using strongly typed hubs reduces runtime errors and improves code maintainability.


πŸ“’ Injecting HubContext in Services

πŸ€” Can we trigger SignalR events outside the Hub class?
πŸ’‘ Yes! By injecting IHubContext, we can send messages from any service.

Example: Sending Messages from a Service Class

using Microsoft.AspNetCore.SignalR;
using MySignalRProject.Hubs;
using MySignalRProject.Hubs.Interfaces;

namespace MySignalRProject.Services
{
    public class MyService
    {
        private readonly IHubContext<ChatHub, IClientChatHub> _hubContext;

        public MyService(IHubContext<ChatHub, IClientChatHub> hubContext)
        {
            _hubContext = hubContext;
        }

        public async Task PerformSomeWork()
        {
            // Perform some logic...
            var result = "Task completed βœ…";

            // Notify clients in 'myGroup'
            await _hubContext.Clients.Group("myGroup").ReceiveMessage(result);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

πŸ“Œ What is IHubContext<ChatHub, IClientChatHub>?

  • ChatHub: The SignalR Hub class.
  • IClientChatHub: The strongly-typed client event interface

βœ… This approach allows you to send real-time updates from anywhere in your backend!


🎯 Conclusion

πŸŽ‰ Now you have a working real-time chat backend using SignalR in .NET Core!

πŸ› οΈ Key Takeaways:
βœ… SignalR enables real-time two-way communication
βœ… Using Groups ensures messages go to the right audience
βœ… Strongly typed hubs prevent typos & enforce method safety
βœ… HubContext allows triggering real-time updates from services

πŸš€ What’s Next?
πŸ”Ή Implement authentication & authorization for enhanced security πŸ”
πŸ”Ή Add message persistence using a database πŸ“¦
πŸ”Ή Scale SignalR using Redis for distributed applications 🌍

Happy coding! πŸ’»βœ¨

Top comments (1)

Collapse
 
suraj_rauniyar_12788fabe7 profile image
Suraj Rauniyar β€’

Thanks for sharing this valuable information...

πŸ‘‹ Kindness is contagious

Explore a trove of insights in this engaging article, celebrated within our welcoming DEV Community. Developers from every background are invited to join and enhance our shared wisdom.

A genuine "thank you" can truly uplift someone’s day. Feel free to express your gratitude in the comments below!

On DEV, our collective exchange of knowledge lightens the road ahead and strengthens our community bonds. Found something valuable here? A small thank you to the author can make a big difference.

Okay