ASP.NET Core SignalR:集線器Hubs
- 2019 年 10 月 3 日
- 筆記
一、什麼是集線器hubs
通過SignalR的集線器hubs中定義的方法,伺服器可以調用連接中的客戶端定義的方法,而客戶端也可以調用伺服器端集線器中定義的方法。SignalR負責實現了客戶端和伺服器之間的實時通訊。
二、配置SignalR的hubs
SignalR通過在Startup.ConfigureServices中調用services.AddSignalR()來配置中間件服務。
services.AddSignalR()
將 SignalR 功能添加到 ASP.NET Core 應用程式時,通過在Startup.Configure方法中調用app.UseSignalR來設置 SignalR 路由。
app.UseSignalR(routes => { routes.MapHub<BaseHub>("/Hub"); });
三、創建集線器Hubs
通過繼承Hub類來創建集線器類,並添加public修飾的方法。可以通過特性[HubMethodName]來修改方法的名稱。
public async Task SendMessage(string user,string message) { await Clients.All.SendAsync("ReceiveMessage", user, message); }
注意:
- 客戶端只能調用集線器類中定義的public的方法。
- 每次客戶端訪問伺服器的集線器類的時候都是在新的對象實例上運行的,所以不能將狀態存儲在集線器類中。
- SignalR的程式碼是非同步模式的,所以集線器中的方法也都是非同步的。
四、參數和返回類型
將集線器類和客戶端接收程式碼改為如下所示:
public class paramsEntity { public string user { get; set; } public string message { get; set; } } public async Task SendMessage(paramsEntity param) { await Clients.All.SendAsync("ReceiveMessage", param); }
//接收伺服器端消息ReceiveMessage的處理程式 connection.on("ReceiveMessage", function (param) { if (param.user) $('#content').append(param.user + ":"); if (param.message) $('#content').append(param.message + ":"); }); //發送消息至伺服器端SendMessage方法 connection.invoke("SendMessage", { user, message }).catch(function (err) { return console.error(err.toString()); });
通過運行可以發現,SignalR會通過序列化和反序列化來處理複雜的參數和返回類型。如果客戶端傳遞的參數和伺服器端不一致會導致方法無法被匹配到而報錯以下錯誤。
Microsoft.AspNetCore.SignalR.HubException: Failed to invoke 'SendMessage' due to an error on the server.
所以使用自定義對象作為參數更加的靈活多變。
五、Hub的對象
1、Context
Hub類具有一個上下文Context,包含連接中的以下屬性以及方法。
| 屬性 | 描述 |
| ConnectionId | 獲取由 SignalR 分配的連接的唯一 ID。每個連接都有一個連接 ID |
| UserIdentifier | 獲取用戶標識符。 默認情況下,SignalR 使用ClaimTypes.NameIdentifier與連接ClaimsPrincipal關聯的作為用戶標識符。 |
| User | 獲取與ClaimsPrincipal當前用戶關聯的。 |
| Items | 獲取可用於在此連接的範圍內共享數據的鍵/值集合。數據可以存儲在此集合中,它將在不同的集線器方法調用中持久保存。 |
| Features | 獲取連接上的可用功能的集合。目前,在大多數情況下不需要此集合,因此不會對其進行詳細介紹。 |
| ConnectionAborted | 獲取一個CancellationToken,它將在連接中止時通知。 |
| 方法 | 描述 |
| GetHttpContext | 返回連接HttpContext的null,如果連接不與 HTTP 請求關聯,則為。對於 HTTP 連接,可以使用此方法來獲取 HTTP 標頭和查詢字元串等資訊。 |
| Abort | 中止連接。 |
2、Clients
Hub類的Clients屬性包含伺服器和客戶端之間通訊的方法和屬性。
| 屬性 | 描述 |
| All | 在所有連接的客戶端上調用方法 |
| Caller | 在調用集線器方法的客戶端上調用方法 |
| Others | 在所有連接的客戶端上調用方法,但調用方法的客戶端除外 |
| 方法 | 描述 |
| AllExcept | 在所有連接的客戶端(指定的連接除外)上調用方法 |
| Client | 在特定連接的客戶端上調用方法 |
| Clients | 在多個特定連接的客戶端上調用方法 |
| Group | 對指定組中的所有連接調用方法 |
| GroupExcept | 對指定組中的所有連接調用方法,指定的連接除外 |
| Groups | 在多組連接上調用方法 |
| OthersInGroup | 對一組連接調用方法,而不包括調用該集線器方法的客戶端 |
| User | 對與特定用戶關聯的所有連接調用方法 |
| Users | 對與指定用戶相關聯的所有連接調用方法 |
表中的每個屬性或方法都返回一個SendAsync包含方法的對象。 SendAsync方法允許你提供要調用的客戶端方法的名稱和參數。
六、強類型的hub
使用SendAsync的時候需要傳入字元串來指定調用客戶端的方法,這就會導致拼寫錯誤等問題引發程式運行錯誤。
通過使用強類型Hub<T>將客戶端的方法約定為介面,這樣Hub的Clients的將會禁用Sendasync方法,而只能調用我們約定的介面方法。
public interface IHub { Task ReceiveMessage(string user, string message); Task ReceiveMessage(string message); }
public class BaseHub : Hub<IHub> { public async Task SendMessage(string user, string message) { await Clients.All.ReceiveMessage(user, message); } }
七、處理連接事件
SignalR的hub提供OnConnectedAsync和OnDisconnectedAsync虛擬方法來管理和跟蹤連接。 重寫OnConnectedAsync虛擬方法,以便在客戶端連接到集線器時執行操作,如將其添加到組。
public override async Task OnConnectedAsync() { await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users"); await base.OnConnectedAsync(); }
重寫OnDisconnectedAsync虛擬方法,以便在客戶端斷開連接時執行操作。 如果客戶端故意斷開連接(例如connection.stop(),通過調用),則exception參數將為null。 但是,如果客戶端由於錯誤(例如網路故障)而斷開連接,則exception參數將包含描述失敗的異常。
public override async Task OnDisconnectedAsync(Exception exception) { await Groups.RemoveFromGroupAsync(Context.ConnectionId, "SignalR Users"); await base.OnDisconnectedAsync(exception); }
