KHÔNG GIAN HỌC TẬP / SignalR
Danh mục bài học Blazor Server .NET 10
BÀI 11Kết nối & dữ liệu

SignalR

Khi server cần chủ động gửi dữ liệu cho client. Tìm hiểu Hub, cách kết nối, gửi nhận tin nhắn và phân phối dữ liệu theo nhóm.

Giải thích, ví dụ & thực hành Tất cả bài học
Từ request/response đến realtime

Đọc luồng Client → Hub → Client, xem mã triển khai rồi thử bảng mô phỏng bên dưới. Bảng mô phỏng chỉ chạy trong component; nó không mở kết nối tới một ChatHub thật.


1️⃣ Tổng quan về SignalR

SignalR là thư viện của ASP.NET Core dùng để xây dựng chức năng realtime giữa server và client.

Khác với HTTP thông thường (client gửi request rồi chờ response), SignalR giữ kết nối mở giữa client và server để:

  • Server có thể chủ động đẩy dữ liệu xuống client
  • Client có thể gửi dữ liệu lên server theo thời gian thực
  • Nhiều client có thể nhận cùng một message ngay lập tức

SignalR rất phù hợp cho các chức năng như: chat realtime, thông báo realtime, dashboard realtime, game, tracking trạng thái, collaborative app...

Xem sơ đồ luồng hoạt động

Client A ─┐
          ├── SignalR Hub (Server) ──> Broadcast / Send / Group / User
Client B ─┤
          └── Server có thể đẩy message realtime xuống các client

2️⃣ Hub là gì?

Hub là trung tâm giao tiếp realtime trong SignalR.

Bạn có thể hiểu Hub giống như một “điểm kết nối” để client và server gọi lẫn nhau:

  • Client gọi method trên Hub
  • Hub xử lý logic phía server
  • Hub gửi message xuống một hoặc nhiều client

Hầu hết các ứng dụng SignalR đều bắt đầu bằng việc tạo một class kế thừa từ Hub.

Xem code Hub cơ bản

using Microsoft.AspNetCore.SignalR;

public class ChatHub : Hub
{
}

3️⃣ Đăng ký SignalR trong Program.cs

Để dùng SignalR, cần làm 2 bước:

  • AddSignalR() để đăng ký service
  • MapHub<THub>("/hub-url") để ánh xạ endpoint Hub

Đây là bước tương tự như Web API dùng AddControllers() và MapControllers().

Xem code Program.cs

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();

// Đăng ký SignalR
builder.Services.AddSignalR();

var app = builder.Build();

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();

app.MapBlazorHub();
app.MapFallbackToPage("/_Host");

// Map Hub
app.MapHub<ChatHub>("/chathub");

app.Run();

4️⃣ Tạo Hub hoàn chỉnh

Một Hub thường sẽ có các method để:

  • Nhận dữ liệu từ client
  • Gửi message đến tất cả client
  • Gửi đến client hiện tại, user cụ thể hoặc group

Ví dụ đơn giản nhất là chat realtime: client gửi tên và nội dung, server nhận rồi broadcast lại cho mọi người.

Xem code ChatHub đầy đủ

using Microsoft.AspNetCore.SignalR;

public class ChatHub : Hub
{
    public async Task SendMessage(string user, string message)
    {
        await Clients.All.SendAsync("ReceiveMessage", user, message);
    }

    public override async Task OnConnectedAsync()
    {
        await Clients.All.SendAsync("ReceiveSystemMessage",
            $"{Context.ConnectionId} connected");

        await base.OnConnectedAsync();
    }

    public override async Task OnDisconnectedAsync(Exception? exception)
    {
        await Clients.All.SendAsync("ReceiveSystemMessage",
            $"{Context.ConnectionId} disconnected");

        await base.OnDisconnectedAsync(exception);
    }
}

5️⃣ Kết nối từ Blazor đến Hub

Phía Blazor, ta dùng HubConnectionBuilder để tạo kết nối đến Hub.

Quy trình thường là:

  • Tạo HubConnection
  • Đăng ký các handler nhận message bằng On<T>(...)
  • Gọi StartAsync() để kết nối

Khi không dùng nữa, cần DisposeAsync() để giải phóng kết nối.

Xem code kết nối Hub trong Blazor

using Microsoft.AspNetCore.SignalR.Client;

private HubConnection? _hubConnection;

protected override async Task OnInitializedAsync()
{
    _hubConnection = new HubConnectionBuilder()
        .WithUrl(Nav.ToAbsoluteUri("/chathub"))
        .WithAutomaticReconnect()
        .Build();

    _hubConnection.On<string, string>("ReceiveMessage", (user, message) =>
    {
        _messages.Add($"{user}: {message}");
        InvokeAsync(StateHasChanged);
    });

    await _hubConnection.StartAsync();
}

6️⃣ Gửi message từ client lên server

Sau khi kết nối thành công, client có thể gọi method trên Hub bằng InvokeAsync().

Ví dụ: gọi method SendMessage để gửi tên và nội dung lên server.

Xem code gửi message

private async Task Send()
{
    if (_hubConnection is not null)
    {
        await _hubConnection.InvokeAsync("SendMessage", _userName, _message);
    }
}

7️⃣ Nhận message từ server xuống client

Để nhận message, client đăng ký callback bằng On<...>().

Ví dụ:

  • Server gọi Clients.All.SendAsync("ReceiveMessage", ...)
  • Client đã đăng ký On<string, string>("ReceiveMessage", ...)
  • Callback sẽ chạy ngay khi message đến

Đây là phần tạo nên tính realtime của SignalR.

Xem code nhận message

_hubConnection.On<string, string>("ReceiveMessage", (user, message) =>
{
    _messages.Add($"{user}: {message}");
    InvokeAsync(StateHasChanged);
});

8. Thử luồng chat bằng mô phỏng nội bộ

Bàn thực hành gửi / nhận Mô phỏng · Không kết nối Hub riêng

Bắt đầu mô phỏng, nhập tên và gửi thử một tin nhắn. Muốn hai trình duyệt trao đổi thật, cần triển khai ChatHub và dùng SignalR Client theo mã mẫu bên dưới.

Trạng thái: Mô phỏng đã dừng

Không tạo kết nối SignalR riêng trong bài mô phỏng này.

Chưa có tin nhắn. Nhật ký gần nhất sẽ xuất hiện tại đây.

Mã tham khảo: component kết nối SignalR thật
@page "/signalr-demo"
@implements IAsyncDisposable
@inject NavigationManager Nav

using Microsoft.AspNetCore.SignalR.Client;

private HubConnection? _hubConnection;
private List<string> _messages = new();
private string _userName = "PLC & SCADA";
private string _message = "";
private bool _isConnected = false;
private string _connectionInfo = "-";

private async Task ConnectHub()
{
    if (_hubConnection is not null)
        return;

    _hubConnection = new HubConnectionBuilder()
        .WithUrl(Nav.ToAbsoluteUri("/chathub"))
        .WithAutomaticReconnect()
        .Build();

    _hubConnection.On<string, string>("ReceiveMessage", (user, message) =>
    {
        _messages.Add($"{user}: {message}");
        InvokeAsync(StateHasChanged);
    });

    _hubConnection.On<string>("ReceiveSystemMessage", (message) =>
    {
        _messages.Add($"[System] {message}");
        InvokeAsync(StateHasChanged);
    });

    await _hubConnection.StartAsync();

    _isConnected = true;
    _connectionInfo = _hubConnection.ConnectionId ?? "-";
}

private async Task SendMessage()
{
    if (_hubConnection is null || string.IsNullOrWhiteSpace(_message))
        return;

    await _hubConnection.InvokeAsync("SendMessage", _userName, _message);
    _message = "";
}

public async ValueTask DisposeAsync()
{
    if (_hubConnection is not null)
    {
        await _hubConnection.DisposeAsync();
    }
}

Logs:


    9️⃣ Group, User và Broadcast

    SignalR hỗ trợ nhiều kiểu gửi message:

    • Clients.All → gửi cho tất cả client
    • Clients.Caller → gửi cho client hiện tại
    • Clients.Others → gửi cho mọi client trừ client hiện tại
    • Clients.User(userId) → gửi cho một user cụ thể
    • Clients.Group(groupName) → gửi cho một group

    Đây là lý do SignalR rất mạnh khi làm chat room, notification room, dashboard theo từng nhóm người dùng.

    Xem code ví dụ Group
    
    public async Task JoinGroup(string groupName)
    {
        await Groups.AddToGroupAsync(Context.ConnectionId, groupName);
        await Clients.Group(groupName).SendAsync("ReceiveSystemMessage",
            $"{Context.ConnectionId} joined {groupName}");
    }
    
    public async Task SendGroupMessage(string groupName, string user, string message)
    {
        await Clients.Group(groupName).SendAsync("ReceiveMessage", user, message);
    }
    

    🔟 Tổng kết

    • SignalR dùng để giao tiếp realtime giữa server và client.
    • Hub là trung tâm nhận và gửi message realtime.
    • Dùng AddSignalR() và MapHub<THub>() để đăng ký trong ASP.NET Core.
    • Phía Blazor dùng HubConnectionBuilder để kết nối đến Hub.
    • Dùng InvokeAsync() để client gọi method trên server.
    • Dùng On<...>() để client nhận message từ server.
    • SignalR rất phù hợp cho chat, notification, dashboard realtime và collaborative app.
    Web hosting by Somee.com