ASP.NET Core SignalR Swift client (Máy khách Swift)
SignalR Swift là thư viện máy khách (client library) để kết nối với máy chủ SignalR từ các ứng dụng Swift. Tài liệu này cung cấp tổng quan về cách cài đặt client, thiết lập kết nối, xử lý lệnh gọi từ máy chủ đến client, gọi phương thức máy chủ, làm việc với phản hồi streaming, và cấu hình kết nối lại tự động cùng các tùy chọn khác.
Cài đặt gói SignalR client
Thư viện SignalR Swift client được phân phối dưới dạng gói Swift. Bạn có thể thêm nó vào dự án bằng Swift Package Manager.
Yêu cầu
- Swift >= 5.10
- macOS >= 11.0
- iOS >= 14
Cài đặt bằng Swift Package Manager
Thêm gói SignalR Swift làm dependency trong tệp Package.swift:
// swift-tools-version: 5.10
import PackageDescription
let package = Package(
name: "signalr-client-app",
dependencies: [
.package(url: "https://github.com/dotnet/signalr-client-swift", branch: "main")
],
targets: [
.executableTarget(name: "YourTargetName", dependencies: [.product(name: "SignalRClient", package: "signalr-client-swift")])
]
)Sau khi thêm dependency, nhập thư viện vào code Swift của bạn:
import SignalRClient
Kết nối đến hub
Để thiết lập kết nối, tạo một HubConnectionBuilder và cấu hình nó với URL của máy chủ SignalR bằng phương thức withUrl(). Sau khi kết nối được tạo, gọi start() để kết nối đến máy chủ:
import SignalRClient
let connection = HubConnectionBuilder()
.withUrl(url: "https://your-signalr-server")
.build()
try await connection.start()Gọi phương thức client từ hub
Để nhận tin nhắn từ máy chủ, đăng ký một handler bằng phương thức on. Phương thức on nhận tên phương thức hub và một closure sẽ được thực thi khi máy chủ gọi phương thức đó.
Trong ví dụ sau, tên phương thức là ReceiveMessage. Tên đối số là user và message:
await connection.on("ReceiveMessage") { (user: String, message: String) in
print("\(user) says: \(message)")
}Code trong connection.on chạy khi code phía máy chủ gọi nó bằng phương thức SendAsync:
using Microsoft.AspNetCore.SignalR;
namespace SignalRChat.Hubs;
public class ChatHub : Hub
{
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
}SignalR xác định phương thức client nào cần gọi bằng cách khớp tên phương thức và các đối số được định nghĩa trong SendAsync và connection.on.
Thực hành tốt nhất là gọi try await connection.start() trên HubConnection sau on. Điều này đảm bảo các handler được đăng ký trước khi nhận bất kỳ tin nhắn nào.
Gọi phương thức hub từ client
Swift client có thể gọi các phương thức hub trên máy chủ bằng phương thức invoke hoặc send của HubConnection. Phương thức invoke chờ phản hồi từ máy chủ và ném lỗi nếu lệnh gọi thất bại, trong khi phương thức send không chờ phản hồi.
Trong code sau, tên phương thức trên hub là SendMessage. Đối số thứ hai và thứ ba truyền vào invoke ánh xạ tới các đối số user và message của phương thức hub:
// Using invoke, which waits for a response try await connection.invoke(method: "SendMessage", arguments: "myUser", "Hello") // Using send, which does not wait for a response try await connection.send(method: "SendMessage", arguments: "myUser", "Hello")
Phương thức invoke trả về với giá trị trả về (nếu có) khi phương thức trên máy chủ trả về. Nếu phương thức trên máy chủ ném lỗi, hàm sẽ ném lỗi.
Ghi log (Logging)
Thư viện Swift client bao gồm một hệ thống ghi log nhẹ được thiết kế cho các ứng dụng Swift. Nó cung cấp cách có cấu trúc để ghi log tin nhắn ở các mức độ nghiêm trọng khác nhau, sử dụng log handler có thể tùy chỉnh. Trên nền tảng Apple, nó tận dụng os.Logger để ghi log hệ thống hiệu quả, trong khi trên các nền tảng khác, nó sử dụng đầu ra console tiêu chuẩn.
Mức log
Sử dụng HubConnectionBuilder().withLogLevel(LogLevel:) để đặt mức log. Tin nhắn được ghi log ở mức được chỉ định và cao hơn:
LogLevel.debug: Thông tin chi tiết hữu ích để gỡ lỗi.LogLevel.information: Tin nhắn ứng dụng chung.LogLevel.warning: Cảnh báo về các vấn đề tiềm ẩn.LogLevel.error: Lỗi cần được chú ý ngay lập tức.
Kết quả client
Ngoài việc gọi phương thức máy chủ, máy chủ có thể gọi các phương thức trên client và chờ phản hồi. Để hỗ trợ điều này, định nghĩa một handler client trả về kết quả từ closure của nó:
await connection.on("ClientResult") { (message: String) in
return "client response"
}Ví dụ, máy chủ có thể gọi phương thức ClientResult trên client và chờ giá trị trả về:
public class ChatHub : Hub
{
public async Task TriggerClientResult()
{
var message = await Clients.Client(connectionId).InvokeAsync<string>("ClientResult");
}
}Làm việc với phản hồi streaming
Để nhận luồng dữ liệu từ máy chủ, sử dụng phương thức stream. Phương thức trả về một stream mà bạn có thể lặp qua bất đồng bộ:
let streamResult: any StreamResult<String> = try await connection.stream(method: "StreamMethod")
for try await item in streamResult.stream {
print("Received item: \(item)")
}Xử lý kết nối bị mất
Kết nối lại tự động
SignalR Swift client hỗ trợ kết nối lại tự động. Để bật tính năng này, gọi withAutomaticReconnect() khi xây dựng kết nối. Kết nối lại tự động bị tắt theo mặc định.
let connection = HubConnectionBuilder()
.withUrl(url: "https://your-signalr-server")
.withAutomaticReconnect()
.build()Khi không có tham số, withAutomaticReconnect() cấu hình client để chờ 0, 2, 10 và 30 giây tương ứng trước mỗi lần kết nối lại. Sau bốn lần thất bại, client ngừng thử kết nối lại.
Trước khi bắt đầu bất kỳ lần kết nối lại nào, HubConnection chuyển sang trạng thái Reconnecting và kích hoạt các callback onReconnecting.
Sau khi kết nối lại thành công, HubConnection chuyển sang trạng thái connected và kích hoạt các callback onReconnected.
Cách thông dụng để sử dụng onReconnecting và onReconnected là đánh dấu các thay đổi trạng thái kết nối:
connection.onReconnecting { error in
// connection is disconnected because of error
}
connection.onReconnected {
// connection is connected back
}Cấu hình chiến lược kết nối lại tự động
Để tùy chỉnh hành vi kết nối lại, bạn có thể truyền một mảng số đại diện cho độ trễ tính bằng giây trước mỗi lần kết nối lại. Để kiểm soát chi tiết hơn, truyền một đối tượng tuân theo giao thức RetryPolicy.
Sử dụng mảng giá trị độ trễ
let connection = HubConnectionBuilder()
.withUrl(url: "https://your-signalr-server")
.withAutomaticReconnect([0, 0, 1]) // Wait 0, 0, and 1 second before each reconnect attempt; stop after 3 attempts.
.build()Sử dụng retry policy tùy chỉnh
Triển khai giao thức RetryPolicy để kiểm soát thời gian kết nối lại:
// Define a custom retry policy
struct CustomRetryPolicy: RetryPolicy {
func nextRetryInterval(retryContext: RetryContext) -> TimeInterval? {
// For example, retry every 1 second indefinitely.
return 1
}
}
let connection = HubConnectionBuilder()
.withUrl(url: "https://your-signalr-server")
.withAutomaticReconnect(CustomRetryPolicy())
.build()Cấu hình tùy chọn timeout và keep-alive
Bạn có thể tùy chỉnh cài đặt timeout và keep-alive của client thông qua HubConnectionBuilder:
| Tùy chọn | Giá trị mặc định | Mô tả |
|---|---|---|
| withKeepAliveInterval | 15 (giây) | Xác định khoảng thời gian client gửi tin nhắn ping. Cài đặt này cho phép máy chủ phát hiện các ngắt kết nối cứng, chẳng hạn khi client rút phích cắm máy tính khỏi mạng. Gửi bất kỳ tin nhắn nào từ client sẽ đặt lại bộ đếm thời gian. Nếu client không gửi tin nhắn trong khoảng ClientTimeoutInterval được đặt trên máy chủ, máy chủ coi client đã ngắt kết nối. |
| withServerTimeout | 30 (giây) | Xác định khoảng thời gian client chờ phản hồi từ máy chủ trước khi coi máy chủ đã ngắt kết nối. |
Cấu hình transport (phương thức vận chuyển)
SignalR Swift client hỗ trợ ba loại transport: LongPolling, ServerSentEvents, và WebSockets. Theo mặc định, client sử dụng WebSockets nếu máy chủ hỗ trợ, và chuyển sang ServerSentEvents và LongPolling nếu không. Bạn có thể cấu hình client sử dụng một transport cụ thể bằng cách gọi withUrl(url:transport:) khi xây dựng kết nối.
let connection = HubConnectionBuilder()
.withUrl(url: "https://your-signalr-server", transport: .webSockets) // use websocket only
.build()let connection = HubConnectionBuilder()
.withUrl(url: "https://your-signalr-server", transport: [.webSockets, .serverSentEvents]) // use websockets and server sent events
.build()