BLOG · .NET · REAL TIME

SignalR for your notifications? You may not need it

Illustration: a server-to-client arrow, the Server-Sent Events principle

Real time = SignalR. That's the reflex. Except that 80% of the time, you just want to send data from the server to the client. Nothing else.

Notifications, dashboards, progress bars, activity feeds... it's all server-to-client push. And the client? The rest of the time, it calls your REST API to act. Like it always has.

The real need for bidirectional is: chat, multiplayer games, collaborative whiteboards... cases where the client talks as much as the server.

The native answer: Server-Sent Events

If you only need to push real-time info from back to front, look at Server-Sent Events (SSE). It's native, lightweight, and does exactly that: server-to-client push. And .NET 10 makes the server-side implementation even simpler.

On the back end, it's standard HTTP: one connection that stays open. Your business actions push typed events onto it, async, without blocking a thread:

// A minimal SSE endpoint
app.MapGet("/notifications", async (HttpContext ctx, CancellationToken ct) =>
{
    ctx.Response.Headers.ContentType = "text/event-stream";
    await foreach (var notif in queue.ReadAllAsync(ct))
    {
        await ctx.Response.WriteAsync($"event: {notif.Type}\ndata: {notif.Json}\n\n", ct);
        await ctx.Response.Body.FlushAsync(ct);
    }
});

On the front, EventSource is native in every modern browser, zero library to install. The front connects once, receives, checks the type, reacts:

const source = new EventSource('/notifications');
source.addEventListener('order', e => refresh(JSON.parse(e.data)));

To put it simply: it's like installing a doorbell. The delivery person rings, drops the parcel and leaves. You're not stuck behind the door waiting, and you know right away when you've been delivered.

SignalR / SSE: the comparison

SignalR gives you: bidirectional by default, a mandatory front-end lib, auto fallback (WebSocket, SSE, Long Polling), native mobile clients, group management.

SSE gives you: unidirectional (server to client), zero lib, native browser reconnection, readable HTTP in your devtools.

The trade-off: SSE is web only. No native EventSource on iOS, Android, React Native or Flutter: third-party libs required. SignalR ships clients for all those platforms.

What about scaling?

SignalR needs a backplane (Redis, Azure SignalR Service...) so your instances can talk. SSE has the same "problem". But nothing stops you from plugging in your own pub/sub (Redis, RabbitMQ...).

My experience

Personally, I used SignalR by default. Until I worked on a queue-management system for a football stadium entrance: pushing positions in real time to screens, with zero need for the client to reply. SSE did the job, without the complexity.

Takeaway: SSE doesn't replace SignalR. It's just that you don't always need a tank to go get bread.

This article comes from one of my LinkedIn posts (in French): join the discussion ↗