SignalR 2

This section documents ASP.NET MVC 5.3.x, ASP.NET Web API 2.2, ASP.NET Web Pages 3, OWIN/Katana, SignalR 2, and ASP.NET Identity 2 — all running on .NET Framework 4.8.1 — the System.Web-hosted MVC framework, its routing, Razor views, HTML helpers, model binding, filters, and the OWIN-based authentication/Identity stack — as described by the official documentation at Microsoft Learn (plus Web API, Web Pages, SignalR, and Identity), which are the reference these pages are written and verified against.

This is not ASP.NET Core MVC. ASP.NET MVC 5 is the pre-Core, System.Web-hosted MVC framework; it is functionally frozen and receives only security fixes. For the current, cross-platform MVC framework see MVC Controllers and Views under ASP.NET Core (Blazor).

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production.

This section’s bibliography lists the reference material consulted while preparing these pages.

This page documents SignalR 2 on .NET Framework 4.8.1 — not ASP.NET Core SignalR, a rewritten library with a different client protocol and hub API (see the comparison at the end of this page).

Hubs and persistent connections

SignalR 2 offers two abstraction levels: the low-level PersistentConnection (raw message send/receive, rarely used directly) and the high-level Hub, which exposes server methods clients call directly (an RPC-like model) and lets the server call back into client-side JavaScript/.NET methods:

public class ChatHub : Hub
{
    public void Send(string user, string message)
        => Clients.All.receiveMessage(user, message);   // calls a client-side "receiveMessage" function
}

Startup.MapSignalR()

SignalR 2 is OWIN-hosted (see Authentication, Identity, and OWIN for the shared OWIN pipeline) even inside an otherwise System.Web-hosted MVC 5 application:

[assembly: OwinStartup(typeof(MyApp.Startup))]
namespace MyApp
{
    public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.MapSignalR();                    // maps hubs at /signalr by default
        }
    }
}

Hub methods, Clients.All/Caller/Group/User, groups

public class ChatHub : Hub
{
    public override Task OnConnected()
    {
        Clients.Caller.welcome("Connected!");
        return base.OnConnected();
    }

    public Task JoinRoom(string room)
        => Groups.Add(Context.ConnectionId, room);

    public Task SendToRoom(string room, string message)
        => Clients.Group(room).receiveMessage(Context.User.Identity.Name, message);

    public Task SendToUser(string userId, string message)
        => Clients.User(userId).receiveMessage(message);   // requires a configured IUserIdProvider
}

Clients.All broadcasts to every connected client; Clients.Caller targets only the invoking connection; Clients.Group(name) targets connections added to a named group (Groups.Add/Groups.Remove, tracked server-side, not persisted — groups must be rejoined in OnConnected after a reconnect); Clients.User(id) targets all of one user’s connections (across tabs/devices) via IUserIdProvider.

The JavaScript client and the .NET client

// generated hub proxies (/signalr/hubs, auto-generated from server-side Hub classes)
var chat = $.connection.chatHub;
chat.client.receiveMessage = function (user, message) { appendMessage(user, message); };

$.connection.hub.start().done(function () {
    chat.server.send("Alice", "Hello!");
});
// .NET client (Microsoft.AspNet.SignalR.Client) -- e.g. a WPF app or a service talking to a SignalR 2 server
var connection = new HubConnection("https://example.com/");
var chat = connection.CreateHubProxy("ChatHub");
chat.On<string, string>("receiveMessage", (user, message) => Console.WriteLine($"{user}: {message}"));
await connection.Start();
await chat.Invoke("Send", "Alice", "Hello!");

Transports and fallback

SignalR 2 auto-negotiates the best available transport and falls back automatically: WebSocketsServer-Sent EventsForever Frame (IE-only, a hidden iframe kept perpetually loading) → long polling (the universal fallback — repeated short-lived HTTP requests). This negotiation is what let SignalR 2 target IIS/System.Web environments and older browsers where WebSockets might be unavailable (Windows Server versions without WebSocket support, corporate proxies that block Upgrade headers), at the cost of client code that must tolerate any of the four.

Authorization on hubs

[Authorize]
public class ChatHub : Hub
{
    [Authorize(Roles = "Support")]
    public void BroadcastAlert(string message) => Clients.All.alert(message);
}

Microsoft.AspNet.SignalR’s `[Authorize] is a separate attribute from System.Web.Mvc.AuthorizeAttribute (see Filters) but relies on the same IPrincipal/ClaimsPrincipal established by the OWIN authentication middleware.

Scale-out backplanes

A single SignalR 2 server holds connections in memory, so scaling to multiple servers (a web farm) requires a backplane to fan messages out across instances — Clients.All.someMethod(…​) on one server must reach clients connected to every other server:

// NuGet: Microsoft.AspNet.SignalR.SqlServer / .Redis / .ServiceBus
GlobalHost.DependencyResolver.UseSqlServer("Data Source=...;Initial Catalog=SignalR;Integrated Security=True");
// or: GlobalHost.DependencyResolver.UseRedis("server", 6379, "password", "signalr-app");
// or: GlobalHost.DependencyResolver.UseServiceBus(connectionString, "signalr-app");

SQL Server, Redis, and Azure Service Bus are the three officially supported backplanes; Redis is the most common choice for throughput-sensitive deployments.

How SignalR 2 differs from ASP.NET Core SignalR

SignalR 2 ASP.NET Core SignalR

Hosting

OWIN, inside or alongside System.Web

ASP.NET Core middleware (app.MapHub<T>())

Wire protocol

SignalR 2’s own JSON protocol

A newer protocol supporting JSON and MessagePack, with a documented spec

Client generation

/signalr/hubs auto-generated JS proxy

No server-generated proxy; clients call connection.invoke("MethodName", …​) directly

Strongly typed hubs

Not built in

Hub<T> gives compile-time-checked client calls

Streaming

Not supported

IAsyncEnumerable<T>/ChannelReader<T> streaming methods

Scale-out

SQL Server / Redis / Azure Service Bus backplanes

Redis backplane, or Azure SignalR Service

See SignalR for ASP.NET Core SignalR, and Introduction to SignalR and the SignalR 2 documentation index for this page’s material.

Next: Authentication, Identity, and OWIN covers the OWIN pipeline SignalR 2 is hosted on in more depth.