Loading...

.NET SignalR: The Bridge for Real-Time Applications

This blog post introduces .NET SignalR, a powerful library designed to add real-time functionality to modern web applications. SignalR simplifies persistent, bidirectional connections between servers and clients, enabling interactive experiences like live chat, notifications, and gaming. The article highlights its integration with Minimal APIs and provides a basic usage example, emphasizing its capability to build fast and lightweight real-time services for developers.

.NET SignalR: The Bridge for Real-Time Applications (ASP.NET Core Minimal API Example)

Today's modern web applications aim to do much more than just serve static content. Interactive experiences like live chat rooms, real-time notifications, live sports scores, games, or collaboration tools increase the demand for instant communication. While the traditional HTTP request-response model falls short for such scenarios, there's a need for solutions that provide instant data flow from server to client. This is where .NET SignalR comes in!

In this blog post, we will explore what SignalR is, its primary purpose, the advantages it offers, and how it can be used, especially in conjunction with Minimal APIs introduced with .NET 9, through a simple example.

What is .NET SignalR?

SignalR is an open-source library developed by Microsoft that enables ASP.NET developers to add real-time functionality to web applications. It facilitates bidirectional and persistent connections between the server and clients (web browsers, mobile apps, etc.). SignalR automatically manages different transport mechanisms like WebSockets, Server-Sent Events (SSE), and Long Polling, choosing the most suitable connection method between the client and server.

Purpose and Benefits of SignalR

The main purpose of SignalR is to simplify real-time web functionality by providing the ability to “push” data from the server to the client. Traditionally, clients would have to continuously check for new data (polling), which led to unnecessary network traffic and server load. SignalR eliminates this problem.

Key benefits of using SignalR:

  • Real-Time Communication: Facilitates the development of applications requiring instant updates, such as chat applications, live scoreboards, notification systems, and collaborative tools.

  • Simple API: Offers an easy-to-use API without requiring developers to deal with the low-level details of complex connection management, WebSockets, or other real-time technologies.

  • Automatic Transport Management: Automatically selects transport methods like WebSockets, Server-Sent Events, and Long Polling, and manages fallback mechanisms. Developers don't need to worry about browser compatibility or network conditions.

  • Broad Client Support: Provides client libraries for JavaScript, .NET (C#), Java (Android), Swift (iOS), making it possible to develop real-time applications on various platforms.

  • High Scalability: Can be distributed across multiple servers and integrated with cloud services like Azure SignalR Service to support millions of concurrent connections.

  • Groups and Users: You can categorize connections into groups or send messages to specific users, making it easier to deliver messages to targeted audiences.

Example Usage of SignalR with ASP.NET Core Minimal API

While Minimal APIs with .NET 9 offer an excellent option for building lightweight and fast APIs, when combined with SignalR, they form an ideal combination for creating powerful real-time microservices.

Below is an example demonstrating how to set up the backend of a simple chat application using SignalR with a Minimal API:

1. Install NuGet Packages:

Add the Microsoft.AspNetCore.SignalR package to your project:

Install-Package Microsoft.AspNetCore.SignalR

2. Program.cs Configuration (Minimal API):

To integrate SignalR into your Minimal API application, modify your Program.cs file as follows:

// Program.cs
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System.Threading.Tasks;

var builder = WebApplication.CreateBuilder(args);

// Add SignalR services
builder.Services.AddSignalR();
builder.Services.AddCors(options =>
{
    options.AddDefaultPolicy(builder =>
    {
        builder.WithOrigins("http://localhost:port", "http://127.0.0.1:port") // Add your client's address here
               .AllowAnyHeader()
               .AllowAnyMethod()
               .AllowCredentials();
    });
});


var app = builder.Build();

// Enable CORS
app.UseCors();

// Enable routing
app.UseRouting();

// Map SignalR Hub
app.MapHub<ChatHub>("/chatHub");

// Minimal API endpoints
app.MapGet("/", () => "Real-Time Application with SignalR!");
app.MapGet("/send-message", async (string user, string message, IHubContext<ChatHub> hubContext) =>
{
    await hubContext.Clients.All.SendAsync("ReceiveMessage", user, message);
    return Results.Ok($"Message sent: {user}: {message}");
});


app.Run();

// SignalR Hub class
public class ChatHub : Hub
{
    public async Task SendMessage(string user, string message)
    {
        // Send the message to all connected clients
        await Clients.All.SendAsync("ReceiveMessage", user, message);
    }
}

Code Explanation:

  • builder.Services.AddSignalR();: Adds SignalR services to the DI container.

  • builder.Services.AddCors(...): If connecting from a different origin on the client side, you need to configure CORS settings. AllowCredentials() is important.

  • app.UseCors();: Enables the CORS middleware.

  • app.MapHub<ChatHub>("/chatHub");: Maps the ChatHub class to the /chatHub URL. Clients will connect to the Hub via this URL.

  • ChatHub class: Represents the SignalR Hub. Clients can call methods on this Hub (e.g., SendMessage). Using Clients.All.SendAsync(), the Hub can send data to all connected clients by invoking a method named ReceiveMessage.

  • /send-message Minimal API endpoint: This endpoint can be used to send a message to the SignalR Hub via an external HTTP request. Messages can also be sent from outside the Hub by injecting IHubContext<ChatHub>.

3. Client-Side (Simple JavaScript Example):

You can connect to this Hub with an HTML file and simple JavaScript.

<!DOCTYPE html>
<html>
<head>
    <title>SignalR Minimal API Chat</title>
    <style>
        body { font-family: sans-serif; margin: 20px; }
        #messagesList { list-style-type: none; padding: 0; }
        #messagesList li { background-color: #f0f0f0; margin-bottom: 5px; padding: 8px; border-radius: 4px; }
        #messageInput { width: 300px; padding: 8px; }
        #userInput { width: 100px; padding: 8px; }
        button { padding: 8px 15px; cursor: pointer; }
    </style>
</head>
<body>
    <h1>SignalR Chat</h1>
    <div id="connectionStatus">Connection status: Disconnected</div>
    <hr />
    <div>
        User: <input type="text" id="userInput" value="Anonymous" />
        Message: <input type="text" id="messageInput" />
        <button id="sendButton" disabled>Send</button>
    </div>
    <hr />
    <ul id="messagesList"></ul>

    <!-- Add SignalR JavaScript client library -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/8.0.0/signalr.min.js"></script>
    <script>
        const connection = new signalR.HubConnectionBuilder()
            .withUrl("https://localhost:port/chatHub") // Use the correct address and port of your API
            .withAutomaticReconnect()
            .build();

        const connectionStatus = document.getElementById("connectionStatus");
        const sendButton = document.getElementById("sendButton");
        const userInput = document.getElementById("userInput");
        const messageInput = document.getElementById("messageInput");
        const messagesList = document.getElementById("messagesList");

        // Listen for ReceiveMessage event
        connection.on("ReceiveMessage", (user, message) => {
            const li = document.createElement("li");
            li.textContent = `${user}: ${message}`;
            messagesList.appendChild(li);
        });

        // Update connection status
        connection.onreconnecting(() => {
            connectionStatus.textContent = "Connection status: Reconnecting...";
            sendButton.disabled = true;
        });

        connection.onreconnected(() => {
            connectionStatus.textContent = "Connection status: Connected.";
            sendButton.disabled = false;
        });

        connection.onclose(() => {
            connectionStatus.textContent = "Connection status: Disconnected.";
            sendButton.disabled = true;
            // If automatic reconnect is off, you might consider restarting the connection here.
        });

        // Start the connection
        connection.start()
            .then(() => {
                connectionStatus.textContent = "Connection status: Connected.";
                sendButton.disabled = false;
                console.log("SignalR connection successful.");
            })
            .catch(err => {
                connectionStatus.textContent = `Connection status: Error - ${err}`;
                console.error(err);
            });

        // Listen for click event on send button
        sendButton.addEventListener("click", () => {
            const user = userInput.value;
            const message = messageInput.value;
            if (user && message) {
                // Invoke SendMessage method on the Hub
                connection.invoke("SendMessage", user, message)
                    .catch(err => console.error(err));
                messageInput.value = ""; // Clear message input
            }
        });
    </script>
</body>
</html>

Running the Example:

  1. Copy the C# code above into Program.cs of an ASP.NET Core Minimal API project.

  2. Check your SSL port in appsettings.json and update the https://localhost:port/chatHub part in the JavaScript code accordingly.

  3. Run the application (dotnet run).

  4. Open the HTML file in a web browser.

  5. Open the same HTML file in different browser windows to see the chat working in real-time.

Conclusion

.NET SignalR is a powerful library that incredibly simplifies adding real-time capabilities to your web applications. When combined with Minimal APIs, it offers an ideal combination for building fast, lightweight, and high-performance real-time services. From live chats to real-time analytics dashboards, SignalR allows you to enrich the user experience and enhance your application's interactivity in many scenarios.

If you are working on a project that requires real-time features, you should definitely take the time to explore the power of .NET SignalR and Minimal APIs!