SignalR āđāļ ASP.NET Core 2026: āļāļđāđāļĄāļ·āļāļāļĢāļāļāđāļ§āļāļŠāļģāļŦāļĢāļąāļ Real-Time, Hubs āđāļĨāļ°āļāļģāļāļēāļĄāļŠāļąāļĄāļ āļēāļĐāļāđāļāļēāļ
āđāļĢāļĩāļĒāļāļĢāļđāđ SignalR āđāļ ASP.NET Core āļŠāļģāļŦāļĢāļąāļāļāļēāļĢāļŠāļ·āđāļāļŠāļēāļĢ real-time āđāļāļāļŠāļāļāļāļēāļ āļāļđāđāļĄāļ·āļāļāļĢāļāļāđāļ§āļāđāļāļĩāđāļĒāļ§āļāļąāļ Hubs, Groups, āļāļēāļĢāļĒāļ·āļāļĒāļąāļāļāļąāļ§āļāļ, āļāļēāļĢ scale āļāđāļ§āļĒ Redis āđāļĨāļ°āļāļģāļāļēāļĄāļŠāļąāļĄāļ āļēāļĐāļāđāļāļēāļāđāļāļāļāļīāļ

SignalR āļāđāļ§āļĒāđāļŦāđāļāļēāļĢāļŠāļ·āđāļāļŠāļēāļĢāđāļāļāļŠāļāļāļāļēāļ real-time āļĢāļ°āļŦāļ§āđāļēāļ server āđāļĨāļ° client āđāļāđāļāļāļāļĨāļīāđāļāļāļąāļ ASP.NET Core āđāļāđāļāđāļāđāļāđ āļāđāļēāļāļāļēāļāļĢāļđāļāđāļāļ request-response HTTP āđāļāļāļāļąāđāļāđāļāļīāļĄ SignalR āļĢāļąāļāļĐāļēāļāļēāļĢāđāļāļ·āđāļāļĄāļāđāļāđāļāļāļāļēāļ§āļĢāļāļĩāđāļāđāļ§āļĒāđāļŦāđ server āļŠāļēāļĄāļēāļĢāļāļŠāđāļāļāļēāļĢāļāļąāļāđāļāļāđāļāļĒāļąāļ client āđāļāđāļāļąāļāļāļĩâāļāļķāđāļāļāļģāđāļāđāļāļŠāļģāļŦāļĢāļąāļāđāļāļāļāļĨāļīāđāļāļāļąāļāđāļāļ, āđāļāļāļāļāļĢāđāļāđāļāļāļŠāļ, āļāļēāļĢāđāļāđāđāļāļĢāđāļ§āļĄāļāļąāļ āđāļĨāļ°āļāļēāļĢāđāļāđāļāđāļāļ·āļāļ real-time
SignalR āđāļĨāļ·āļāļ transport āļāļĩāđāļāļĩāļāļĩāđāļŠāļļāļāļāļĩāđāļĄāļĩāļāļĒāļđāđāđāļāļĒāļāļąāļāđāļāļĄāļąāļāļī: WebSockets āļāđāļāļ āļāļēāļāļāļąāđāļ Server-Sent Events āđāļĨāđāļ§ Long Polling āļāļĨāđāļ fallback āļāļĩāđāļāđāļ§āļĒāđāļŦāđāļĄāļąāđāļāđāļāļ§āđāļēāļŠāļēāļĄāļēāļĢāļāđāļāđāļāļēāļāđāļāđāļāļąāļāļāļļāļāđāļāļĢāļēāļ§āđāđāļāļāļĢāđāđāļĨāļ°āļāļēāļĢāļāļģāļŦāļāļāļāđāļēāđāļāļĢāļ·āļāļāđāļēāļĒāđāļāļĒāđāļĄāđāļāđāļāļāđāļāļĨāļĩāđāļĒāļāđāļāļĨāļāđāļāđāļ
āļ§āļīāļāļĩāļāļēāļĢāļāļģāļāļēāļāļāļāļ SignalR Hubs āļŠāļģāļŦāļĢāļąāļāļāļēāļĢāļŠāļ·āđāļāļŠāļēāļĢ Server-Client
Hub āļāļģāļŦāļāđāļēāļāļĩāđāđāļāđāļ pipeline āļĢāļ°āļāļąāļāļŠāļđāļāļāļĩāđāļāļąāļāļāļēāļĢāļāļēāļĢāđāļĢāļĩāļĒāļ method āļĢāļ°āļŦāļ§āđāļēāļ client āđāļĨāļ° server Client āđāļĢāļĩāļĒāļ method āļāļ hub āđāļĨāļ° hub āļŠāļēāļĄāļēāļĢāļāđāļĢāļĩāļĒāļ method āļāļ client āļāļĩāđāđāļāļ·āđāļāļĄāļāđāļāļāļĒāļđāđ āļāļēāļĢ abstraction āļāļĩāđāļāđāļ§āļĒāļĨāļāļāļ§āļēāļĄāļāļąāļāļāđāļāļāđāļāļāļēāļĢāļāļąāļāļāļēāļĢāļāļēāļĢāđāļāļ·āđāļāļĄāļāđāļ WebSocket āļāđāļ§āļĒāļāļāđāļāļ
āļāļąāļ§āļāļĒāđāļēāļāļāđāļāđāļāļāļĩāđāđāļŠāļāļ chat hub āļāļ·āđāļāļāļēāļāļāļĩāđāļŠāđāļāļāđāļāļāļ§āļēāļĄāđāļāļĒāļąāļ client āļāļĩāđāđāļāļ·āđāļāļĄāļāđāļāļāļąāđāļāļŦāļĄāļ:
using Microsoft.AspNetCore.SignalR;
public class ChatHub : Hub
{
// Called when a client sends a message
public async Task SendMessage(string user, string message)
{
// Broadcast to ALL connected clients
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
// Called automatically when a client connects
public override async Task OnConnectedAsync()
{
await Clients.Caller.SendAsync("Connected", Context.ConnectionId);
await base.OnConnectedAsync();
}
// Called automatically when a client disconnects
public override async Task OnDisconnectedAsync(Exception? exception)
{
// Clean up resources, notify other users, etc.
await base.OnDisconnectedAsync(exception);
}
}Property Clients āđāļŦāđāļāļēāļĢāđāļāđāļēāļāļķāļ client āļāļĩāđāđāļāļ·āđāļāļĄāļāđāļāļāļąāđāļāļŦāļĄāļāļāđāļēāļāļāļąāļ§āđāļĨāļ·āļāļ targeting āļāđāļēāļāđ: All, Caller, Others, Group āđāļĨāļ° User
āļāļēāļĢāļāļģāļŦāļāļāļāđāļē SignalR āđāļ ASP.NET Core 9
āļāļēāļĢāļĨāļāļāļ°āđāļāļĩāļĒāļ SignalR āđāļ ASP.NET Core 9 āđāļāđāļĢāļđāļāđāļāļ middleware āļĄāļēāļāļĢāļāļēāļ āļāļēāļĢāļāļģāļŦāļāļāļāđāļēāļāđāļēāļāļĨāđāļēāļāļāļĩāđāđāļāļīāļāđāļāđāļāļēāļāđāļāļĢāđāļāļāļāļĨ JSON āđāļĨāļ° MessagePack āļāļĢāđāļāļĄāļāļāļēāļ buffer āļāļĩāđāļāļģāļŦāļāļāđāļāļ:
var builder = WebApplication.CreateBuilder(args);
// Add SignalR services with configuration
builder.Services.AddSignalR(options =>
{
options.EnableDetailedErrors = builder.Environment.IsDevelopment();
options.MaximumReceiveMessageSize = 64 * 1024; // 64 KB
options.StreamBufferCapacity = 10;
options.KeepAliveInterval = TimeSpan.FromSeconds(15);
options.ClientTimeoutInterval = TimeSpan.FromSeconds(30);
})
.AddJsonProtocol(options =>
{
options.PayloadSerializerOptions.PropertyNamingPolicy = null; // PascalCase
});
var app = builder.Build();
// Map the hub endpoint
app.MapHub<ChatHub>("/chathub");
app.Run();āļāļēāļĢāļāļąāđāļāļāđāļē KeepAliveInterval āđāļĨāļ° ClientTimeoutInterval āļāļ§āļāļāļļāļĄāļāļēāļĢāļāļĢāļ§āļāļŠāļāļāļŠāļāļēāļāļ°āļāļēāļĢāđāļāļ·āđāļāļĄāļāđāļ Client āļāļĩāđāđāļĄāđāļāļāļāļŠāļāļāļāļ āļēāļĒāđāļāļāđāļ§āļ timeout āļāļ°āļāļđāļāļāļīāļāļēāļĢāļāļēāļ§āđāļēāļāļđāļāļāļąāļāļāļēāļĢāđāļāļ·āđāļāļĄāļāđāļ
āļāļēāļĢāļāļąāļāļāļēāļĢ Groups āļŠāļģāļŦāļĢāļąāļāļāļēāļĢāļŠāđāļāļāđāļāļāļ§āļēāļĄāđāļāļāđāļāļēāļ°āļāļ
Groups āđāļŦāđāļāļĨāđāļāđāļāļāļēāļĢāļāļąāļāļĢāļ°āđāļāļĩāļĒāļāļāļēāļĢāđāļāļ·āđāļāļĄāļāđāļāđāļĨāļ°āļŠāđāļāļāđāļāļāļ§āļēāļĄāđāļāļĒāļąāļāļāļĨāļļāđāļĄāļĒāđāļāļĒāļāļāļ client āļāļĢāļāļĩāļāļēāļĢāđāļāđāļāļēāļāļāļąāđāļ§āđāļāđāļāļĩāđāļĒāļ§āļāđāļāļāļāļąāļ chat room āļāļĩāđāļāļđāđāđāļāđāđāļāđāļēāļĢāđāļ§āļĄāļŦāđāļāļāđāļāļāļēāļ°āđāļĨāļ°āļĢāļąāļāļāđāļāļāļ§āļēāļĄāļāļēāļāļŦāđāļāļāļāļąāđāļāđāļāđāļēāļāļąāđāļ
public class GroupChatHub : Hub
{
// Add the current connection to a group
public async Task JoinRoom(string roomName)
{
await Groups.AddToGroupAsync(Context.ConnectionId, roomName);
// Notify the group that someone joined
await Clients.Group(roomName).SendAsync(
"UserJoined",
Context.User?.Identity?.Name ?? "Anonymous"
);
}
// Remove the current connection from a group
public async Task LeaveRoom(string roomName)
{
await Groups.RemoveFromGroupAsync(Context.ConnectionId, roomName);
await Clients.Group(roomName).SendAsync(
"UserLeft",
Context.User?.Identity?.Name ?? "Anonymous"
);
}
// Send a message to a specific group only
public async Task SendToRoom(string roomName, string message)
{
await Clients.Group(roomName).SendAsync(
"ReceiveMessage",
Context.User?.Identity?.Name,
message
);
}
}āļāļēāļĢāđāļāđāļāļŠāļĄāļēāļāļīāļ group āļāļđāļāļāļąāļāļāļēāļĢāđāļāļ·āđāļāļĄāļāđāļ āđāļĄāđāđāļāđāļāļđāđāđāļāđ āđāļĄāļ·āđāļāļāļđāđāđāļāđ reconnect āļāđāļāļāđāļāđāļēāļĢāđāļ§āļĄ group āļāļĩāļāļāļĢāļąāđāļ āļŠāļģāļŦāļĢāļąāļāļāļēāļĢāđāļāđāļāļŠāļĄāļēāļāļīāļ group āđāļāļāļāļēāļ§āļĢ āđāļŦāđāđāļāđāļāļāļēāļĢāđāļāļ·āđāļāļĄāđāļĒāļ group āđāļāļāļēāļāļāđāļāļĄāļđāļĨāđāļĨāļ°āđāļāđāļēāļĢāđāļ§āļĄāļāļĩāļāļāļĢāļąāđāļāđāļāļĒāļāļąāļāđāļāļĄāļąāļāļīāđāļ OnConnectedAsync
Groups āļĄāļĩāļāļĒāļđāđāđāļāļŦāļāđāļ§āļĒāļāļ§āļēāļĄāļāļģāđāļāđāļēāļāļąāđāļāđāļĨāļ°āđāļĄāđāļāļđāļāđāļāđāļāļĢāļąāļāļĐāļēāļŦāļĨāļąāļāļāļēāļ server restart āļŦāļĢāļ·āļāđāļāļŠāļāļēāļāļāļēāļĢāļāđ scaled-out āđāļāļĒāđāļĄāđāļĄāļĩ backplane āļŠāļģāļŦāļĢāļąāļāļāļēāļĢ deployment production āļāļąāļāļŦāļĨāļēāļĒ server āđāļŦāđāđāļāđ Redis āļŦāļĢāļ·āļ Azure SignalR Service āđāļāđāļ backplane
āļāļēāļĢāļĢāļąāļāļĐāļēāļāļ§āļēāļĄāļāļĨāļāļāļ āļąāļĒāļāļēāļĢāđāļāļ·āđāļāļĄāļāđāļ SignalR āļāđāļ§āļĒāļāļēāļĢāļĒāļ·āļāļĒāļąāļāļāļąāļ§āļāļ
SignalR āļāļģāļāļēāļāļĢāđāļ§āļĄāļāļąāļāļāļēāļĢāļĒāļ·āļāļĒāļąāļāļāļąāļ§āļāļ ASP.NET Core Attribute [Authorize] āļāļģāļāļąāļāļāļēāļĢāđāļāđāļēāļāļķāļ hub āđāļāļāļēāļ°āļāļđāđāđāļāđāļāļĩāđāļĒāļ·āļāļĒāļąāļāļāļąāļ§āļāļāđāļĨāđāļ§ āđāļĨāļ° Context.User āđāļŦāđāļāļēāļĢāđāļāđāļēāļāļķāļ claims āļāļāļāļāļđāđāđāļāđāļāļĩāđāļĒāļ·āļāļĒāļąāļāļāļąāļ§āļāļāđāļĨāđāļ§
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.SignalR;
[Authorize] // Require authentication for the entire hub
public class SecureHub : Hub
{
// Access user claims through Context.User
public async Task SendPrivateMessage(string recipientUserId, string message)
{
var senderName = Context.User?.Identity?.Name
?? throw new HubException("User not authenticated");
// Send to a specific user (all their connections)
await Clients.User(recipientUserId).SendAsync(
"PrivateMessage",
senderName,
message
);
}
[Authorize(Roles = "Admin")] // Role-based authorization on method
public async Task BroadcastAnnouncement(string announcement)
{
await Clients.All.SendAsync("Announcement", announcement);
}
}āļŠāļģāļŦāļĢāļąāļāļāļēāļĢāđāļāļ·āđāļāļĄāļāđāļ WebSocket āļāđāļāļāļŠāđāļ token āļĒāļ·āļāļĒāļąāļāļāļąāļ§āļāļāļāđāļēāļ query string āđāļāļ·āđāļāļāļāļēāļ WebSocket āđāļĄāđāļĢāļāļāļĢāļąāļ custom headers āļāļģāļŦāļāļāļāđāļē JavaScript client āđāļŦāđāļĢāļ§āļĄ token:
import * as signalR from "@microsoft/signalr";
const connection = new signalR.HubConnectionBuilder()
.withUrl("/securehub", {
accessTokenFactory: () => localStorage.getItem("authToken") || ""
})
.withAutomaticReconnect()
.build();
await connection.start();āļāļāļāļąāđāļ server āļāļģāļŦāļāļāļāđāļēāļāļēāļĢāļĒāļ·āļāļĒāļąāļāļāļąāļ§āļāļ JWT āđāļāļ·āđāļāļāđāļēāļ token āļāļēāļ query string:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
// Read token from query string for SignalR
var accessToken = context.Request.Query["access_token"];
var path = context.HttpContext.Request.Path;
if (!string.IsNullOrEmpty(accessToken) &&
path.StartsWithSegments("/securehub"))
{
context.Token = accessToken;
}
return Task.CompletedTask;
}
};
});āļāļĢāđāļāļĄāļāļĩāđāļāļ°āļāļīāļāļīāļāļāļēāļĢāļŠāļąāļĄāļ āļēāļĐāļāđ .NET āđāļĨāđāļ§āļŦāļĢāļ·āļāļĒāļąāļāļāļĢāļąāļ?
āļāļķāļāļāļāļāđāļ§āļĒāļāļąāļ§āļāļģāļĨāļāļāđāļāļāđāļāđāļāļāļ, flashcards āđāļĨāļ°āđāļāļāļāļāļŠāļāļāđāļāļāļāļīāļāļāļĢāļąāļ
āļāļēāļĢ Scale SignalR āļāđāļ§āļĒ Redis Backplane
āđāļāļŠāļ āļēāļāđāļ§āļāļĨāđāļāļĄ load-balanced client āļāļēāļāđāļāļ·āđāļāļĄāļāđāļāļāļąāļ server instance āļāļĩāđāđāļāļāļāđāļēāļāļāļąāļ āļŦāļēāļāđāļĄāđāļĄāļĩ backplane āļāđāļāļāļ§āļēāļĄāļāļĩāđāļŠāđāļāļāļēāļ server āļŦāļāļķāđāļāļāļ°āđāļāļāļķāļāđāļāļāļēāļ° client āļāļĩāđāđāļāļ·āđāļāļĄāļāđāļāļāļąāļ server āļāļąāđāļ Redis āļāļģāļŦāļāđāļēāļāļĩāđāđāļāđāļ backplane āđāļāļ·āđāļāļāļīāļāđāļāļĢāđāļāļāđāļāđāļāļāļ§āļēāļĄāļāđāļēāļĄāļāļļāļ server instance
builder.Services.AddSignalR()
.AddStackExchangeRedis(options =>
{
options.Configuration = builder.Configuration
.GetConnectionString("Redis");
// Optional: configure Redis-specific options
options.Configuration.ChannelPrefix =
RedisChannel.Literal("MyApp_SignalR_");
});Redis backplane publish āļāđāļāļāļ§āļēāļĄ SignalR āļāļąāđāļāļŦāļĄāļāđāļāļĒāļąāļ Redis channels āđāļāđāļĨāļ° server instance subscribe āđāļāļĒāļąāļ channels āđāļŦāļĨāđāļēāļāļĩāđāđāļĨāļ°āļŠāđāļāļāđāļāļāļ§āļēāļĄāđāļāļĒāļąāļ client āđāļāđāļāļĢāļ·āđāļāļ āļ§āļīāļāļĩāļāļĩāđāđāļāļīāđāļĄ latency āļāđāļāļĒāļĄāļēāļ (āđāļāļĒāļāļąāđāļ§āđāļ 1-2ms) āđāļāļāļāļ°āļāļĩāđāļāđāļ§āļĒāđāļŦāđāļŠāļēāļĄāļēāļĢāļ horizontal scaling āđāļāđ
āļŠāļģāļŦāļĢāļąāļāļāļēāļĢ deployment āļĢāļ°āļāļąāļ enterprise Azure SignalR Service āđāļŦāđāļāļēāļāđāļĨāļ·āļāļāļāļĩāđāļāļąāļāļāļēāļĢāđāļāļĒāļāļąāļāđāļāļĄāļąāļāļīāļāļķāđāļāļāļąāļāļāļēāļĢ scaling, āļāļēāļĢāļāļąāļāļāļēāļĢāļāļēāļĢāđāļāļ·āđāļāļĄāļāđāļ āđāļĨāļ°āļāļ§āļēāļĄāļāļĢāđāļāļĄāđāļāđāļāļēāļ
Strongly-Typed Hubs āļŠāļģāļŦāļĢāļąāļāļāļ§āļēāļĄāļāļĨāļāļāļ āļąāļĒ Compile-Time
Strongly-typed hubs āđāļāļāļāļĩāđ magic strings āļāđāļ§āļĒ interface methods āļāđāļ§āļĒāđāļŦāđāļŠāļēāļĄāļēāļĢāļāļāļĢāļ§āļāļŠāļāļāļāļēāļĢāđāļĢāļĩāļĒāļ method client āđāļāđāļ§āļĨāļē compile:
public interface INotificationClient
{
Task ReceiveNotification(string title, string message, string severity);
Task UpdateProgress(int percentage);
Task TaskCompleted(Guid taskId, bool success);
}
// NotificationHub.cs
public class NotificationHub : Hub<INotificationClient>
{
public async Task NotifyAll(string title, string message)
{
// Compile-time checking - no magic strings
await Clients.All.ReceiveNotification(title, message, "info");
}
public async Task ReportProgress(string groupName, int percentage)
{
// IDE autocomplete works here
await Clients.Group(groupName).UpdateProgress(percentage);
}
}āļāļēāļĢ refactor āļāļĨāļēāļĒāđāļāđāļāđāļĢāļ·āđāļāļāļāļĨāļāļāļ āļąāļĒāļĄāļēāļāļāļķāđāļāđāļāļĢāļēāļ°āļāļēāļĢāđāļāļĨāļĩāđāļĒāļāļāļ·āđāļ method āđāļ interface āļāļ°āđāļŠāļāļāļāļģāđāļŦāļāđāļāļāļēāļĢāđāļĢāļĩāļĒāļāļāļąāđāļāļŦāļĄāļāļāļĩāđāļāđāļāļāļāļąāļāđāļāļāļāļąāļāļāļĩ
Streaming āļāđāļāļĄāļđāļĨāļāđāļ§āļĒ SignalR Channels
SignalR āļĢāļāļāļĢāļąāļ streaming āļŠāļģāļŦāļĢāļąāļāļŠāļāļēāļāļāļēāļĢāļāđāļāļĩāđāļāđāļāļĄāļđāļĨāļāļđāļāļāļĨāļīāļāļāļĩāļĨāļ°āļāđāļāļĒ āđāļāđāļ āļāļēāļĢāļāļąāļāđāļāļāļāļ§āļēāļĄāļāļ·āļāļŦāļāđāļē, log tailing āļŦāļĢāļ·āļāļāđāļāļĄāļđāļĨāđāļāļāđāļāļāļĢāđ real-time āļĢāļāļāļĢāļąāļāļāļąāđāļ streaming āđāļāļ server-to-client āđāļĨāļ° client-to-server
public class StreamingHub : Hub
{
// Server-to-client streaming with IAsyncEnumerable
public async IAsyncEnumerable<StockPrice> StreamStockPrices(
string[] symbols,
[EnumeratorCancellation] CancellationToken cancellationToken)
{
var random = new Random();
while (!cancellationToken.IsCancellationRequested)
{
foreach (var symbol in symbols)
{
yield return new StockPrice
{
Symbol = symbol,
Price = random.NextDouble() * 1000,
Timestamp = DateTime.UtcNow
};
}
await Task.Delay(1000, cancellationToken);
}
}
// Client-to-server streaming
public async Task UploadStream(IAsyncEnumerable<LogEntry> stream)
{
await foreach (var entry in stream)
{
// Process each log entry as it arrives
await ProcessLogEntry(entry);
}
}
}
public record StockPrice(string Symbol, double Price, DateTime Timestamp);
public record LogEntry(string Level, string Message, DateTime Timestamp);JavaScript client āļāļĢāļīāđāļ āļ stream āđāļāļĒāđāļāđ async iterator:
const stream = connection.stream("StreamStockPrices", ["AAPL", "MSFT"]);
stream.subscribe({
next: (price) => console.log(`${price.symbol}: $${price.price}`),
error: (err) => console.error(err),
complete: () => console.log("Stream completed")
});āļāļģāļāļēāļĄāļŠāļąāļĄāļ āļēāļĐāļāđ SignalR āļāļĩāđāļāļāļāđāļāļĒ
āļāļēāļĢāļŠāļąāļĄāļ āļēāļĐāļāđāļāļēāļāđāļāļāļāļīāļāļĄāļąāļāļāļĢāļāļāļāļĨāļļāļĄāļŠāļāļēāļāļąāļāļĒāļāļĢāļĢāļĄ SignalR āđāļĨāļ°āļŠāļāļēāļāļāļēāļĢāļāđāļāļĢāļīāļ āļāļģāļāļēāļĄāļāđāļāđāļāļāļĩāđāļāļĢāļēāļāļāļāđāļāļĒāđāļāļāļēāļĢāļŠāļąāļĄāļ āļēāļĐāļāđ .NET:
āļāļāļīāļāļēāļĒāļāļĢāļ°āļāļ§āļāļāļēāļĢāđāļāļĢāļāļē transport: SignalR āļĨāļāļ WebSockets āļāđāļāļ, fallback āđāļāļĒāļąāļ Server-Sent Events, āļāļēāļāļāļąāđāļ Long Polling āđāļāđāļēāđāļāļ§āđāļēāđāļāđāļĨāļ° transport āļāļđāļāđāļāđāđāļĄāļ·āđāļāđāļāđāļĨāļ°āļāđāļāļāļģāļāļąāļāļāļāļāļĄāļąāļ
āļ: SignalR āļāļąāļāļāļēāļĢāļŠāļāļēāļāļ°āļāļēāļĢāđāļāļ·āđāļāļĄāļāđāļāļāļĒāđāļēāļāđāļĢāđāļĄāļ·āđāļ client āļŦāļĨāļļāļāļāļēāļĢāđāļāļ·āđāļāļĄāļāđāļāļāļąāđāļ§āļāļĢāļēāļ§?
SignalR āļĢāļąāļāļĐāļēāļŠāļāļēāļāļ°āļāļēāļĢāđāļāļ·āđāļāļĄāļāđāļāļāļ server āđāļāļāđāļ§āļāđāļ§āļĨāļēāļāļĩāđāļāļģāļŦāļāļāļāđāļēāđāļāđ āđāļĄāļ·āđāļāđāļāļīāļāđāļāđ automatic reconnection client āļāļ°āļāļĒāļēāļĒāļēāļĄ reconnect āđāļāļĒāđāļāđ connection ID āđāļāļīāļĄ āļŦāļēāļāļŠāļģāđāļĢāđāļ āļāļēāļĢāđāļāļ·āđāļāļĄāļāđāļāļāļ°āļāļģāđāļāļīāļāļāđāļāđāļāļĒāđāļĄāđāļŠāļđāļāđāļŠāļĩāļĒāļāļēāļĢāđāļāđāļāļŠāļĄāļēāļāļīāļ group āļŦāļēāļāļāļēāļĢāļāļąāļāļāļēāļĢāđāļāļ·āđāļāļĄāļāđāļāđāļāļīāļ timeout āļāļ°āļŠāļĢāđāļēāļāļāļēāļĢāđāļāļ·āđāļāļĄāļāđāļāđāļŦāļĄāđāđāļĨāļ° client āļāđāļāļāđāļāđāļēāļĢāđāļ§āļĄ groups āļāļĩāļāļāļĢāļąāđāļ
āļ: āļāļ§āļēāļĄāđāļāļāļāđāļēāļāļĢāļ°āļŦāļ§āđāļēāļ Clients.User() āđāļĨāļ° Clients.Client() āļāļ·āļāļāļ°āđāļĢ?
Clients.User(userId) āđāļāđāļēāļŦāļĄāļēāļĒāđāļāļĒāļąāļāļāļēāļĢāđāļāļ·āđāļāļĄāļāđāļāļāļąāđāļāļŦāļĄāļāļāļĩāđāđāļāđāļāļāļāļāļāļđāđāđāļāđāļāļĩāđāļĒāļ·āļāļĒāļąāļāļāļąāļ§āļāļāđāļāļāļēāļ°âāļĄāļĩāļāļĢāļ°āđāļĒāļāļāđāđāļĄāļ·āđāļāļāļđāđāđāļāđāļŦāļāļķāđāļāļāļāđāļāļīāļāļŦāļĨāļēāļĒ browser tabs Clients.Client(connectionId) āđāļāđāļēāļŦāļĄāļēāļĒāđāļāļĒāļąāļāļāļēāļĢāđāļāļ·āđāļāļĄāļāđāļāđāļāļāļēāļ°āļŦāļāļķāđāļāđāļāļĩāļĒāļ§ āļāļēāļĢ targeting āļāļēāļĄāļāļđāđāđāļāđāļāđāļāļāļāļēāļĢāļāļēāļĢāļĒāļ·āļāļĒāļąāļāļāļąāļ§āļāļāđāļĨāļ°āđāļāđ IUserIdProvider āđāļāļ·āđāļ map āļāļēāļĢāđāļāļ·āđāļāļĄāļāđāļāļāļąāļ user IDs
āļ: āļāļ° implement presence detection (āđāļŠāļāļāļ§āđāļēāđāļāļĢāļāļāļāđāļĨāļāđ) āļāļĒāđāļēāļāđāļĢ?
āļāļīāļāļāļēāļĄāļāļēāļĢāđāļāļ·āđāļāļĄāļāđāļāđāļ OnConnectedAsync āđāļĨāļ° OnDisconnectedAsync āđāļāđāļ mapping user-to-connection āđāļ concurrent dictionary āļŦāļĢāļ·āļ distributed cache āļŠāļģāļŦāļĢāļąāļāļāļēāļĢ deployment āđāļāļ scaled-out āđāļāđ shared store āđāļāđāļ Redis Broadcast āļāļēāļĢāļāļąāļāđāļāļ presence āđāļāļĒāļąāļ groups āļāļĩāđāđāļāļĩāđāļĒāļ§āļāđāļāļāđāļĄāļ·āđāļāļāļđāđāđāļāđ connect āļŦāļĢāļ·āļ disconnect
āļ: āļāļāļīāļāļēāļĒāļāļļāļāļāļĢāļ°āļŠāļāļāđāļāļāļ SignalR backplane
Backplane āļāļīāļāđāļāļĢāđāļāļāđāļāđāļāļāļ§āļēāļĄāļāđāļēāļĄ server instances āļŦāļĨāļēāļĒāļāļąāļ§āđāļāļŠāļ āļēāļāđāļ§āļāļĨāđāļāļĄ load-balanced āļŦāļēāļāđāļĄāđāļĄāļĩ āļāđāļāļāļ§āļēāļĄāļāļĩāđāļŠāđāļāļāļēāļ server A āļāļ°āđāļāļāļķāļāđāļāļāļēāļ° client āļāļĩāđāđāļāļ·āđāļāļĄāļāđāļāļāļąāļ server A Redis āđāļĨāļ° Azure SignalR Service āđāļāđāļāļāļąāļ§āđāļĨāļ·āļāļ backplane āļāļĩāđāļāļāļāđāļāļĒ Backplane publish āļāđāļāļāļ§āļēāļĄāđāļāļĒāļąāļ shared channel āļāļĩāđāļāļļāļ server subscribe
āļāļĨāļĒāļļāļāļāđāļāļēāļĢāđāļāļīāđāļĄāļāļĢāļ°āļŠāļīāļāļāļīāļ āļēāļ
āļāļĢāļ°āļŠāļīāļāļāļīāļ āļēāļ SignalR āļāļķāđāļāļāļĒāļđāđāļāļąāļāļāļāļēāļāļāđāļāļāļ§āļēāļĄ āļāļ§āļēāļĄāļāļĩāđ āđāļĨāļ°āļāļģāļāļ§āļāļāļēāļĢāđāļāļ·āđāļāļĄāļāđāļ āđāļāļāļŠāļēāļĢ best practices āļāļĢāļ°āļŠāļīāļāļāļīāļ āļēāļ ASP.NET Core āđāļŦāđ benchmark āđāļāļĒāļĨāļ°āđāļāļĩāļĒāļ
- āđāļāđāđāļāļĢāđāļāļāļāļĨ MessagePack āļŠāļģāļŦāļĢāļąāļ binary serializationâāļĨāļāļāļāļēāļ payload 30-50% āđāļĄāļ·āđāļāđāļāļĩāļĒāļāļāļąāļ JSON
- Batch āļāđāļāļāļ§āļēāļĄ āđāļĄāļ·āđāļāđāļāđāļāđāļāđāļāđāđāļāļāļāļĩāđāļāļ°āļŠāđāļāļāđāļāļāļ§āļēāļĄāđāļĨāđāļāđ āļŦāļĨāļēāļĒāļāđāļāļāļ§āļēāļĄ
- āļāļģāļāļąāļāļāļāļēāļ group āļāļĩāđāļŦāļĨāļąāļāļāļąāļ members; āļŠāļģāļŦāļĢāļąāļāļāļĨāļļāđāļĄāļāļđāđāļāļĄāļāļĩāđāđāļŦāļāđāļāļ§āđāļē āđāļŦāđāļāļīāļāļēāļĢāļāļēāļĢāļđāļāđāļāļ pub/sub
- āđāļāļīāļāđāļāđ compression āļŠāļģāļŦāļĢāļąāļ payload āļāļĩāđāļĄāļĩ text āđāļĒāļāļ°:
.AddJsonProtocol().AddHubOptions(o => o.EnableDetailedErrors = false) - āļāļąāđāļāļāđāļē timeout āļāļĩāđāđāļŦāļĄāļēāļ°āļŠāļĄ āđāļāļ·āđāļāļāļĨāđāļāļĒ resources āļāļēāļ stale connections āļāļĒāđāļēāļāļĢāļ§āļāđāļĢāđāļ§
// MessagePack configuration for smaller payloads
builder.Services.AddSignalR()
.AddMessagePackProtocol(options =>
{
options.SerializerOptions =
MessagePackSerializerOptions.Standard
.WithCompression(MessagePackCompression.Lz4Block);
});āļŠāļĢāļļāļ
- SignalR abstraction āļāļēāļĢāđāļĨāļ·āļāļ transport (WebSockets, SSE, Long Polling) āđāļĨāļ°āđāļŦāđāđāļĄāđāļāļĨāļāļēāļĢāđāļāļĩāļĒāļāđāļāļĢāđāļāļĢāļĄāļāļĩāđāļŠāļāļāļāļĨāđāļāļāļāļąāļāļŠāļģāļŦāļĢāļąāļāļāļēāļĢāļŠāļ·āđāļāļŠāļēāļĢ real-time
- Hubs āļĢāļ§āļĄāļĻāļđāļāļĒāđāļāļēāļĢāļāļąāļāļāļēāļĢāļāļēāļĢāđāļāļ·āđāļāļĄāļāđāļ; strongly-typed hubs āđāļāļīāđāļĄāļāļ§āļēāļĄāļāļĨāļāļāļ āļąāļĒ compile-time āļŠāļģāļŦāļĢāļąāļāļāļēāļĢāđāļĢāļĩāļĒāļ method client
- Groups āļāđāļ§āļĒāđāļŦāđāļŠāđāļāļāđāļāļāļ§āļēāļĄāđāļāļāđāļāļēāļ°āļāļāđāļāļĒāļąāļāļāļĨāļļāđāļĄāļĒāđāļāļĒāļāļāļāļāļēāļĢāđāļāļ·āđāļāļĄāļāđāļâāđāļāđāļēāļĢāđāļ§āļĄ groups āļāļĩāļāļāļĢāļąāđāļāļŦāļĨāļąāļ reconnection
- āļāļēāļĢāļĒāļ·āļāļĒāļąāļāļāļąāļ§āļāļāļĢāļ§āļĄāđāļāđāļēāļāļąāļ ASP.NET Core identity; āļŠāđāļ token āļāđāļēāļ query string āļŠāļģāļŦāļĢāļąāļāļāļēāļĢāđāļāļ·āđāļāļĄāļāđāļ WebSocket
- Scale āđāļāļ horizontal āļāđāļ§āļĒ Redis backplane āļŦāļĢāļ·āļ Azure SignalR Service āđāļāļ·āđāļāļāļīāļāđāļāļĢāđāļāļāđāļāđāļāļāļ§āļēāļĄāļāđāļēāļĄāļāļļāļ server instances
- Streaming āļĢāļāļāļĢāļąāļāļāļēāļĢāļŠāđāļāļāđāļāļĄāļđāļĨāđāļāļāļāļĩāļĨāļ°āļāđāļāļĒāļāđāļ§āļĒ
IAsyncEnumerableāļŠāļģāļŦāļĢāļąāļāļāļąāđāļāļŠāļāļēāļāļāļēāļĢāļāđ server-to-client āđāļĨāļ° client-to-server
āđāļĢāļīāđāļĄāļāļķāļāļāđāļāļĄāđāļĨāļĒ!
āļāļāļŠāļāļāļāļ§āļēāļĄāļĢāļđāđāļāļāļāļāļļāļāļāđāļ§āļĒāļāļąāļ§āļāļģāļĨāļāļāļŠāļąāļĄāļ āļēāļĐāļāđāđāļĨāļ°āđāļāļāļāļāļŠāļāļāđāļāļāļāļīāļāļāļĢāļąāļ

āđāļāļĩāļĒāļāđāļāļĒ
Anthony Fillion-MailletāļāļąāļāļāļąāļāļāļēāļāļđāļĨāļŠāđāļāļ āļāļđāđāļāđāļāļāļąāđāļ SharpSkill
āđāļāđāļāļāļąāļāļāļąāļāļāļēāļāļđāļĨāļŠāđāļāļāļĄāļēāļāļ§āđāļē 10 āļāļĩ āļāļđāđāļĨ SharpSkill āđāļĨāļ°āļĢāļąāļāļāļīāļāļāļāļāļāļļāļāļŠāļīāđāļāļāļĩāđāđāļāļĒāđāļāļĢāđāļāļĩāđāļāļĩāđ
āļāļąāļāđāļāļāđāļĄāļ·āđāļ 12 āļŠāļīāļāļŦāļēāļāļĄ 2569
āđāļāļĢāđ
āļāļāļāļ§āļēāļĄāļāļĩāđāđāļāļĩāđāļĒāļ§āļāđāļāļ

ASP.NET Core Minimal APIs 2026: āļŠāļāļēāļāļąāļāļĒāļāļĢāļĢāļĄ āļāļĢāļ°āļŠāļīāļāļāļīāļ āļēāļ āđāļĨāļ°āļāļģāļāļēāļĄāļŠāļąāļĄāļ āļēāļĐāļāđāļāļēāļ
āļāļđāđāļĄāļ·āļāļāļāļąāļāļŠāļĄāļāļđāļĢāļāđāđāļāļĩāđāļĒāļ§āļāļąāļ ASP.NET Core Minimal APIs āļāļĢāđāļāļĄāļŠāļāļēāļāļąāļāļĒāļāļĢāļĢāļĄāļŠāļĄāļąāļĒāđāļŦāļĄāđ āļāļēāļĢāđāļāļīāđāļĄāļāļĢāļ°āļŠāļīāļāļāļīāļ āļēāļāļāđāļ§āļĒ Native AOT āđāļĨāļ°āļāļģāļāļēāļĄāļŠāļąāļĄāļ āļēāļĐāļāđāļāļĩāđāļāļāļāđāļāļĒāļŠāļģāļŦāļĢāļąāļāļāļąāļāļāļąāļāļāļē .NET

.NET 10 āđāļāļāļĩ 2026: āļāļĩāđāļāļāļĢāđāđāļŦāļĄāđ Native AOT āđāļĨāļ°āļāļģāļāļēāļĄāļŠāļąāļĄāļ āļēāļĐāļāđāļāļēāļāļāļĩāđāļāđāļāļāļĢāļđāđ
āļŠāļĢāļļāļāļāļĩāđāļāļāļĢāđāđāļŦāļĄāđāļāļāļ .NET 10 LTS āļāļĢāļāļāļāļĨāļļāļĄ Native AOT, C# 14 extension members, field keyword āđāļĨāļ° EF Core 10 āļāļĢāđāļāļĄāļāļģāļāļēāļĄāļŠāļąāļĄāļ āļēāļĐāļāđāļāļēāļāļāļĩāđāļāļāļāđāļāļĒāđāļāļāļĩ 2026

.NET MAUI āđāļāļāļĩ 2026: āļāļēāļĢāļāļąāļāļāļē Cross-Platform āđāļĨāļ°āļāļģāļāļēāļĄāļŠāļąāļĄāļ āļēāļĐāļāđāļāļēāļ
āļāļāļāļ§āļēāļĄāļŠāļāļ .NET MAUI āļāļĢāļāļāļāļĨāļļāļĄāļāļēāļĢāļāļąāļāļāļē cross-platform āļāđāļ§āļĒ .NET 10, handler architecture, MVVM, HybridWebView āđāļĨāļ°āļāļģāļāļēāļĄāļŠāļąāļĄāļ āļēāļĐāļāđāļāļēāļāļāļĩāđāļŠāļģāļāļąāļāđāļāļāļĩ 2026