SignalR āđƒāļ™ ASP.NET Core 2026: āļ„āļđāđˆāļĄāļ·āļ­āļ„āļĢāļšāļ–āđ‰āļ§āļ™āļŠāļģāļŦāļĢāļąāļš Real-Time, Hubs āđāļĨāļ°āļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļ‡āļēāļ™

āđ€āļĢāļĩāļĒāļ™āļĢāļđāđ‰ SignalR āđƒāļ™ ASP.NET Core āļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļŠāļ·āđˆāļ­āļŠāļēāļĢ real-time āđāļšāļšāļŠāļ­āļ‡āļ—āļēāļ‡ āļ„āļđāđˆāļĄāļ·āļ­āļ„āļĢāļšāļ–āđ‰āļ§āļ™āđ€āļāļĩāđˆāļĒāļ§āļāļąāļš Hubs, Groups, āļāļēāļĢāļĒāļ·āļ™āļĒāļąāļ™āļ•āļąāļ§āļ•āļ™, āļāļēāļĢ scale āļ”āđ‰āļ§āļĒ Redis āđāļĨāļ°āļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļ—āļēāļ‡āđ€āļ—āļ„āļ™āļīāļ„

SignalR āđƒāļ™ ASP.NET Core 2026: āļ„āļđāđˆāļĄāļ·āļ­āļ„āļĢāļšāļ–āđ‰āļ§āļ™āļŠāļģāļŦāļĢāļąāļš Real-Time, Hubs āđāļĨāļ°āļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļ‡āļēāļ™

SignalR āļŠāđˆāļ§āļĒāđƒāļŦāđ‰āļāļēāļĢāļŠāļ·āđˆāļ­āļŠāļēāļĢāđāļšāļšāļŠāļ­āļ‡āļ—āļēāļ‡ real-time āļĢāļ°āļŦāļ§āđˆāļēāļ‡ server āđāļĨāļ° client āđƒāļ™āđāļ­āļ›āļžāļĨāļīāđ€āļ„āļŠāļąāļ™ ASP.NET Core āđ€āļ›āđ‡āļ™āđ„āļ›āđ„āļ”āđ‰ āļ•āđˆāļēāļ‡āļˆāļēāļāļĢāļđāļ›āđāļšāļš request-response HTTP āđāļšāļšāļ”āļąāđ‰āļ‡āđ€āļ”āļīāļĄ SignalR āļĢāļąāļāļĐāļēāļāļēāļĢāđ€āļŠāļ·āđˆāļ­āļĄāļ•āđˆāļ­āđāļšāļšāļ–āļēāļ§āļĢāļ—āļĩāđˆāļŠāđˆāļ§āļĒāđƒāļŦāđ‰ server āļŠāļēāļĄāļēāļĢāļ–āļŠāđˆāļ‡āļāļēāļĢāļ­āļąāļ›āđ€āļ”āļ•āđ„āļ›āļĒāļąāļ‡ client āđ„āļ”āđ‰āļ—āļąāļ™āļ—āļĩ—āļ‹āļķāđˆāļ‡āļˆāļģāđ€āļ›āđ‡āļ™āļŠāļģāļŦāļĢāļąāļšāđāļ­āļ›āļžāļĨāļīāđ€āļ„āļŠāļąāļ™āđāļŠāļ—, āđāļ”āļŠāļšāļ­āļĢāđŒāļ”āđāļšāļšāļŠāļ”, āļāļēāļĢāđāļāđ‰āđ„āļ‚āļĢāđˆāļ§āļĄāļāļąāļ™ āđāļĨāļ°āļāļēāļĢāđāļˆāđ‰āļ‡āđ€āļ•āļ·āļ­āļ™ real-time

SignalR Transport Fallback

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 āļ—āļĩāđˆāđ€āļŠāļ·āđˆāļ­āļĄāļ•āđˆāļ­āļ—āļąāđ‰āļ‡āļŦāļĄāļ”:

ChatHub.cscsharp
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 āļ—āļĩāđˆāļāļģāļŦāļ™āļ”āđ€āļ­āļ‡:

Program.cscsharp
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 āļ—āļĩāđˆāļœāļđāđ‰āđƒāļŠāđ‰āđ€āļ‚āđ‰āļēāļĢāđˆāļ§āļĄāļŦāđ‰āļ­āļ‡āđ€āļ‰āļžāļēāļ°āđāļĨāļ°āļĢāļąāļšāļ‚āđ‰āļ­āļ„āļ§āļēāļĄāļˆāļēāļāļŦāđ‰āļ­āļ‡āļ™āļąāđ‰āļ™āđ€āļ—āđˆāļēāļ™āļąāđ‰āļ™

GroupChatHub.cscsharp
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

āļ„āļ§āļēāļĄāļ„āļ‡āļ—āļ™āļ‚āļ­āļ‡ Group

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 āļ‚āļ­āļ‡āļœāļđāđ‰āđƒāļŠāđ‰āļ—āļĩāđˆāļĒāļ·āļ™āļĒāļąāļ™āļ•āļąāļ§āļ•āļ™āđāļĨāđ‰āļ§

SecureHub.cscsharp
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:

signalr-client.tstypescript
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:

Program.cs - JWT configuration for SignalRcsharp
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

Program.cs - Redis backplane configurationcsharp
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:

INotificationClient.cscsharp
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

StreamingHub.cscsharp
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:

streaming-client.tstypescript
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 āļ­āļĒāđˆāļēāļ‡āļĢāļ§āļ”āđ€āļĢāđ‡āļ§
csharp
// 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

āđ€āļ‚āļĩāļĒāļ™āđ‚āļ”āļĒ

Anthony Fillion-Maillet

āļ™āļąāļāļžāļąāļ’āļ™āļēāļŸāļđāļĨāļŠāđāļ•āļ āļœāļđāđ‰āļāđˆāļ­āļ•āļąāđ‰āļ‡ SharpSkill

āđ€āļ›āđ‡āļ™āļ™āļąāļāļžāļąāļ’āļ™āļēāļŸāļđāļĨāļŠāđāļ•āļāļĄāļēāļāļ§āđˆāļē 10 āļ›āļĩ āļ”āļđāđāļĨ SharpSkill āđāļĨāļ°āļĢāļąāļšāļœāļīāļ”āļŠāļ­āļšāļ—āļļāļāļŠāļīāđˆāļ‡āļ—āļĩāđˆāđ€āļœāļĒāđāļžāļĢāđˆāļ—āļĩāđˆāļ™āļĩāđˆ

āļ­āļąāļ›āđ€āļ”āļ•āđ€āļĄāļ·āđˆāļ­ 12 āļŠāļīāļ‡āļŦāļēāļ„āļĄ 2569

āđāļŠāļĢāđŒ

āļšāļ—āļ„āļ§āļēāļĄāļ—āļĩāđˆāđ€āļāļĩāđˆāļĒāļ§āļ‚āđ‰āļ­āļ‡

ASP.NET Core Minimal APIs 2026: āļŠāļ–āļēāļ›āļąāļ•āļĒāļāļĢāļĢāļĄ āļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļž āđāļĨāļ°āļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļ‡āļēāļ™

ASP.NET Core Minimal APIs 2026: āļŠāļ–āļēāļ›āļąāļ•āļĒāļāļĢāļĢāļĄ āļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļž āđāļĨāļ°āļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļ‡āļēāļ™

āļ„āļđāđˆāļĄāļ·āļ­āļ‰āļšāļąāļšāļŠāļĄāļšāļđāļĢāļ“āđŒāđ€āļāļĩāđˆāļĒāļ§āļāļąāļš ASP.NET Core Minimal APIs āļžāļĢāđ‰āļ­āļĄāļŠāļ–āļēāļ›āļąāļ•āļĒāļāļĢāļĢāļĄāļŠāļĄāļąāļĒāđƒāļŦāļĄāđˆ āļāļēāļĢāđ€āļžāļīāđˆāļĄāļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļžāļ”āđ‰āļ§āļĒ Native AOT āđāļĨāļ°āļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļ—āļĩāđˆāļžāļšāļšāđˆāļ­āļĒāļŠāļģāļŦāļĢāļąāļšāļ™āļąāļāļžāļąāļ’āļ™āļē .NET

.NET 10 new features Native AOT C# 14

.NET 10 āđƒāļ™āļ›āļĩ 2026: āļŸāļĩāđ€āļˆāļ­āļĢāđŒāđƒāļŦāļĄāđˆ Native AOT āđāļĨāļ°āļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļ‡āļēāļ™āļ—āļĩāđˆāļ•āđ‰āļ­āļ‡āļĢāļđāđ‰

āļŠāļĢāļļāļ›āļŸāļĩāđ€āļˆāļ­āļĢāđŒāđƒāļŦāļĄāđˆāļ‚āļ­āļ‡ .NET 10 LTS āļ„āļĢāļ­āļšāļ„āļĨāļļāļĄ Native AOT, C# 14 extension members, field keyword āđāļĨāļ° EF Core 10 āļžāļĢāđ‰āļ­āļĄāļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļ‡āļēāļ™āļ—āļĩāđˆāļžāļšāļšāđˆāļ­āļĒāđƒāļ™āļ›āļĩ 2026

.NET MAUI cross-platform development tutorial 2026

.NET MAUI āđƒāļ™āļ›āļĩ 2026: āļāļēāļĢāļžāļąāļ’āļ™āļē Cross-Platform āđāļĨāļ°āļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļ‡āļēāļ™

āļšāļ—āļ„āļ§āļēāļĄāļŠāļ­āļ™ .NET MAUI āļ„āļĢāļ­āļšāļ„āļĨāļļāļĄāļāļēāļĢāļžāļąāļ’āļ™āļē cross-platform āļ”āđ‰āļ§āļĒ .NET 10, handler architecture, MVVM, HybridWebView āđāļĨāļ°āļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļ‡āļēāļ™āļ—āļĩāđˆāļŠāļģāļ„āļąāļāđƒāļ™āļ›āļĩ 2026