SignalR Production

Back

Loading concept...

🚀 SignalR Production: Real-Time Magic at Scale

The Story: Imagine you’re running a super popular pizza delivery service. Customers want to know exactly where their pizza is—right now, not after refreshing the page 100 times. That’s what SignalR does for your apps: instant updates, no refreshing needed!


🎯 What We’re Learning

We’re diving into three superpowers that make SignalR work in the real world:

  1. Transports – The delivery trucks for your messages
  2. Authentication – The ID check at the door
  3. Scaling – Handling millions of hungry customers

🚗 Part 1: SignalR Transports

What Are Transports?

Think of transports as different ways to deliver a letter:

Transport Like… Speed When Used
WebSockets Phone call ⚡ Fastest Best choice!
Server-Sent Events Radio broadcast 🏃 Fast Backup option
Long Polling Asking “Are we there yet?” 🐢 Slowest Last resort

The Pizza Delivery Analogy

  • WebSockets = A direct phone line to the pizza shop. You hear instantly when your pizza moves.
  • Server-Sent Events = Like listening to a radio station that announces pizza locations.
  • Long Polling = Calling the shop every 5 seconds: “Is it here yet? Is it here yet?”

How SignalR Chooses

SignalR is smart! It picks the best transport automatically:

graph TD A["Start Connection"] --> B{WebSockets OK?} B -->|Yes| C["Use WebSockets ⚡"] B -->|No| D{SSE OK?} D -->|Yes| E["Use Server-Sent Events 🏃"] D -->|No| F["Use Long Polling 🐢"]

Code Example: Setting Up Transports

// Server-side: Configure transports
builder.Services.AddSignalR()
    .AddHubOptions<ChatHub>(options =>
    {
        options.EnableDetailedErrors = true;
    });

// Client-side: Connect with options
const connection = new signalR
    .HubConnectionBuilder()
    .withUrl("/chatHub", {
        transport: signalR.HttpTransportType
            .WebSockets
    })
    .build();

Real-World Tip

💡 Always prefer WebSockets! They’re 10x faster and use less server power. Only fall back to others when WebSockets aren’t available (like old browsers).


🔐 Part 2: SignalR Authentication

Why Authentication Matters

Imagine if anyone could track any pizza delivery—chaos! Authentication makes sure:

  • Only logged-in users can connect
  • Users only see their own data
  • Bad actors are blocked

The ID Check at the Door

graph TD A["User Wants to Connect"] --> B{Has Valid Token?} B -->|Yes ✅| C[Welcome! Here's your data] B -->|No ❌| D["Sorry, access denied!"]

Two Ways to Authenticate

Method 1: Cookie Authentication (Easy!)

Like showing your membership card at a club:

// Server: Enable cookie auth
builder.Services.AddAuthentication()
    .AddCookie();

// Hub: Require logged-in users
[Authorize]
public class ChatHub : Hub
{
    public async Task SendMessage(string msg)
    {
        var user = Context.User.Identity.Name;
        await Clients.All
            .SendAsync("ReceiveMessage", user, msg);
    }
}

Method 2: JWT Token (More Secure!)

Like having a special wristband with your name encoded:

// Server: Configure JWT for SignalR
builder.Services.AddAuthentication()
    .AddJwtBearer(options =>
    {
        options.Events = new JwtBearerEvents
        {
            OnMessageReceived = context =>
            {
                // Get token from query string
                var token = context.Request
                    .Query["access_token"];

                if (!string.IsNullOrEmpty(token))
                {
                    context.Token = token;
                }
                return Task.CompletedTask;
            }
        };
    });
// Client: Send token when connecting
const connection = new signalR
    .HubConnectionBuilder()
    .withUrl("/chatHub", {
        accessTokenFactory: () => {
            return localStorage
                .getItem("jwt_token");
        }
    })
    .build();

Getting User Info in Your Hub

public class OrderHub : Hub
{
    public async Task GetMyOrders()
    {
        // Get the logged-in user's ID
        var userId = Context.UserIdentifier;

        // Send only THEIR orders
        await Clients.Caller
            .SendAsync("Orders", GetOrdersFor(userId));
    }
}

Quick Security Checklist

✅ Do This ❌ Avoid This
Use HTTPS always HTTP in production
Validate tokens Trust client data
Set token expiry Tokens that never expire
Log failed attempts Ignoring auth errors

📈 Part 3: SignalR Scaling

The Problem: One Server Isn’t Enough

Your pizza tracker is too popular! One server can handle maybe 10,000 connections. But you have 100,000 hungry customers!

The Solution: Multiple Servers + Backplane

Think of a backplane as a walkie-talkie system:

graph TD A["User A on Server 1"] --> B["Redis Backplane"] C["User B on Server 2"] --> B D["User C on Server 3"] --> B B --> A B --> C B --> D style B fill:#ff6b6b

When Server 1 sends a message, Redis tells Server 2 and Server 3: “Hey, pass this along!”

Setting Up Redis Backplane

// Install: Microsoft.AspNetCore
//         .SignalR.StackExchangeRedis

builder.Services.AddSignalR()
    .AddStackExchangeRedis(
        "localhost:6379",
        options =>
        {
            options.Configuration
                .ChannelPrefix = "MyApp";
        });

That’s it! Now your servers talk to each other through Redis.

Azure SignalR Service (The Easy Button)

Don’t want to manage servers? Let Azure do the heavy lifting:

// Install: Microsoft.Azure.SignalR

builder.Services.AddSignalR()
    .AddAzureSignalR("your-connection-string");

Scaling Options Compared

Option Connections Difficulty Cost
Single Server 10K Easy $
Redis Backplane 100K+ Medium $
Azure SignalR 1M+ Easy $$

Sticky Sessions: The Gotcha!

⚠️ Important! When using load balancers, enable sticky sessions so users stay connected to the same server.

# Nginx example
upstream signalr {
    ip_hash;  # Sticky sessions!
    server server1:5000;
    server server2:5000;
}

Scaling Best Practices

  1. Start simple – One server is fine for small apps
  2. Add Redis – When you hit 5K+ connections
  3. Go Azure – When you need 100K+ and don’t want server headaches
  4. Monitor everything – Track connection counts, message rates, errors

🎉 Putting It All Together

Here’s a production-ready SignalR setup:

var builder = WebApplication.CreateBuilder(args);

// 1. Authentication
builder.Services.AddAuthentication()
    .AddJwtBearer();

// 2. SignalR with Redis scaling
builder.Services.AddSignalR()
    .AddStackExchangeRedis("redis:6379");

var app = builder.Build();

// 3. Secure WebSocket endpoint
app.UseAuthentication();
app.UseAuthorization();

app.MapHub<ChatHub>("/chatHub")
    .RequireAuthorization();

app.Run();

🧠 Key Takeaways

Topic Remember This!
Transports WebSockets = best, Long Polling = backup
Authentication JWT tokens + query string for SignalR
Scaling Redis backplane or Azure SignalR Service

🚀 You’re Ready!

You now understand how SignalR works in production:

  • Transports deliver messages at the speed of light
  • 🔐 Authentication keeps the bad guys out
  • 📈 Scaling handles millions of users

Go build something amazing! Your real-time app is waiting. 🎊

Loading story...

Story - Premium Content

Please sign in to view this story and start learning.

Upgrade to Premium to unlock full access to all stories.

Stay Tuned!

Story is coming soon.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.