ASP.NET Core 9: Tương tác real-time với SignalR (cho người mới bắt đầu)
Posted Date:
Trong bài này, chúng ta sẽ tìm hiểu về SignalR, bao gồm các tiêu chuẩn, quy ước, và thực hành tốt nhất để triển khai giải pháp thời gian thực.
Chúng ta sẽ tạo ứng dụng quản lý công việc theo thời gian thực, áp dụng các kỹ thuật sẵn có của .NET và SignalR để hiểu khái niệm stream (luồng dữ liệu), đồng thời tìm hiểu cách triển khai SignalR trên máy chủ.
Các chủ đề chính
SignalR là gì
Hiểu về khái niệm Server và Client
Làm việc với Streaming
Triển khai ứng dụng SignalR ASP.NET Core
Yêu cầu kỹ thuật
SignalR là gì?
Trong các ứng dụng web, ta có hai phần chính: client (thường là trình duyệt) và server. Client gửi yêu cầu, server xử lý rồi phản hồi lại — theo mô hình request/response tuần tự. Tuy nhiên, có nhiều tình huống đòi hỏi giao tiếp thời gian thực, nơi dữ liệu liên tục được cập nhật — ví dụ:
Ứng dụng bản đồ hiển thị tình trạng giao thông ngay lập tức
Trò chơi trực tuyến
Mạng xã hội
Ứng dụng cộng tác (soạn thảo văn bản, bảng tính…)
Trong những trường hợp đó, client và server cần kênh kết nối liên tục để trao đổi dữ liệu.
SignalR là thư viện của .NET giúp tạo các ứng dụng thời gian thực một cách đơn giản, bằng cách duy trì kết nối hai chiều giữa client và server.
Hình – Các thành phần của SignalR
SignalR sử dụng kết nối chủ động, vận chuyển thông điệp JSON hoặc nhị phân (binary). Mặc định, nó dùng WebSockets, nhưng nếu môi trường không hỗ trợ, sẽ tự động chuyển sang:
Server-Sent Events – kết nối một chiều từ server đến client
Long Polling – client liên tục gửi yêu cầu và chờ phản hồi
Thứ tự ưu tiên là: WebSockets → Server-Sent Events → Long Polling.
Thành phần cốt lõi: Hub
Kết nối giữa client và server được quản lý qua Hub, một lớp đặc biệt của SignalR. Hub cho phép gọi hàm từ xa (RPC – Remote Procedure Call), tức là server có thể thực thi phương thức trên client và ngược lại.
SignalR ẩn toàn bộ sự phức tạp của việc quản lý kết nối, đồng thời hỗ trợ:
Gửi thông báo đến tất cả client
Gửi riêng cho từng client
Gửi theo nhóm client
SignalR hỗ trợ nhiều nền tảng: .NET, Java, JavaScript, thậm chí cả ứng dụng console.
Hiểu về khái niệm Server và Client
SignalR hoạt động dựa trên hai thành phần: Server và Client, tương tự ứng dụng web thông thường, nhưng với khả năng giao tiếp liên tục.
Chúng ta sẽ tìm hiểu mô hình này qua ví dụ: ứng dụng quản lý công việc (TaskManager).
Ứng dụng quản lý công việc (TaskManager)
Ứng dụng TaskManager (dùng Razor Pages) sẽ có các chức năng:
Hoạt động theo thời gian thực
Tạo công việc
Hoàn thành công việc
Hiển thị danh sách công việc đang và đã hoàn thành
Các thành phần của ứng dụng TaskManager
Thành phần chính:
Client (Razor Pages) – giao diện người dùng
index-page.js: quản lý giao tiếp giữa trang chính và server
signalr.js: SDK JavaScript của SignalR
Server (Razor Page app) – đóng vai trò điều phối
Hub – quản lý giao tiếp thời gian thực
Tạo dự án
Mở terminal, chạy:
dotnet new webapp -o TaskManager
cd TaskManager
Tiếp theo, cài SignalR JavaScript SDK bằng công cụ LibMan (Library Manager CLI):
public class TaskManagerHub : Hub
{
public async Task CreateTask(TaskModel taskModel)
{
// ..
}
public async Task CompleteTask(TaskModel taskModel)
{
// ..
}
}
Hub kế thừa từ lớp Hub trong Microsoft.AspNetCore.SignalR. Nó cho phép cả client và server gọi hàm của nhau.
Mô hình dữ liệu
Tạo tệp Models/TaskModel.cs:
public class TaskModel
{
public Guid Id { get; } = Guid.NewGuid();
public string Name { get; set; }
public bool IsCompleted { get; set; }
public TaskModel()
{
IsCompleted = false;
}
public TaskModel(string name) : this()
{
Name = name;
}
public TaskModel(string name, bool isCompleted)
{
Name = name;
IsCompleted = isCompleted;
}
}
Mẹo: Hãy dùng hằng số (constant) cho tên sự kiện, tránh lỗi chính tả khi gọi chuỗi.
Cấu hình server
Trong Program.cs, thêm SignalR và ánh xạ Hub:
using TaskManager.Hubs;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddSignalR();
var app = builder.Build();
app.MapRazorPages();
app.MapHub<TaskManagerHub>("/taskmanagerhub");
app.Run();
Route /taskmanagerhub chính là endpoint mà client sẽ kết nối đến.
HTML này chỉ tạo form nhập tên công việc và hai danh sách hiển thị.
Kết nối đến Hub (index-page.js)
var connection = new signalR.HubConnectionBuilder()
.withUrl("/taskmanagerhub")
.build();
connection.on("NotifyTaskManager", updateTaskList);
connection.start().then(function () {
addTaskButton.disabled = false;
}).catch(function (err) {
console.error(err.toString());
});
function updateTaskList(taskModel) {
// Cập nhật danh sách công việc trên giao diện
}
connection.on() đăng ký sự kiện khi server gửi thông báo.
connection.start() khởi tạo kết nối.
updateTaskList() xử lý dữ liệu trả về.
Mẹo: Dùng đối tượng làm tham số truyền (object-based params) để tránh phải thay đổi chữ ký hàm mỗi khi dữ liệu đổi.
Gửi công việc mới
var addTaskButton = document.getElementById("addTaskButton");
addTaskButton.addEventListener("click", function (event) {
let taskName = document.getElementById("taskName");
connection.invoke("CreateTask", { name: taskName.value })
.catch(function (err) {
console.error(err.toString());
});
taskName.value = "";
taskName.focus();
event.preventDefault();
});
Khi người dùng nhấn “Add Task”, client gọi phương thức CreateTask trên server qua kết nối SignalR.
Luồng giao tiếp giữa Client và Server
Luồng giao tiếp SignalR
Người dùng nhập tên công việc → nhấn Add Task
Client gọi CreateTask() trên server
Server lưu công việc, rồi gọi ngược NotifyTaskManager() trên client
Client nhận dữ liệu và cập nhật giao diện
SignalR giúp đồng bộ hóa hai chiều này gần như ngay lập tức.
Làm việc với Streaming
Streaming trong SignalR là hình thức truyền dữ liệu liên tục giữa client và server. Khác với mô hình request/response truyền thống (chuyển dữ liệu một lần), streaming cho phép dòng dữ liệu chảy liên tục, rất hữu ích cho:
Dashboard trực tiếp
Ứng dụng chat
Bảng tin, số liệu liên tục
Đặc điểm:
Dữ liệu gửi đi ngay khi có sẵn
Bất đồng bộ (asynchronous)
Hai chiều (bidirectional streaming)
Thách thức
Phụ thuộc chất lượng mạng
Tốn tài nguyên (duy trì kết nối mở)
Khó debug
Giới hạn trình duyệt cũ
Cần chú ý bảo mật và khả năng mở rộng
Triển khai ví dụ Streaming
Tạo dự án mới:
mkdir SignalRStream
cd SignalRStream
dotnet new webapp -o SignalRStreamingApp
cd SignalRStreamingApp
code .
Tạo thư mục Hubs và thêm StreamHub.cs:
using Microsoft.AspNetCore.SignalR;
using System.Threading.Channels;
namespace SignalRStream.Hubs;
public class StreamHub : Hub
{
public ChannelReader<int> Countdown(int count)
{
var channel = Channel.CreateUnbounded<int>();
_ = WriteItemsAsync(channel.Writer, count);
return channel.Reader;
}
private async Task WriteItemsAsync(ChannelWriter<int> writer, int count)
{
for (int i = count; i >= 0; i--)
{
await writer.WriteAsync(i);
await Task.Delay(1000); // mô phỏng độ trễ
}
writer.TryComplete();
}
}
Phương thức Countdown() trả về luồng dữ liệu đếm ngược.
Cập nhật Program.cs:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddSignalR();
var app = builder.Build();
app.MapRazorPages();
app.MapHub<StreamHub>("/streamHub");
app.Run();
Để lại một bình luận
Bạn phải đăng nhập để gửi bình luận.