SignalR 是一個用於實現實時網站的 Microsoft .NET 庫。它使用多種技術來實現伺服器與客戶端間的雙向通信,伺服器可以隨時將消息推送到連接的客戶端。 ...
https://weblogs.asp.net/ricardoperes/signalr-in-asp-net-core
作者:Ricardo Peres
譯者:oopsguy.com
介紹
SignalR 是一個用於實現實時網站的 Microsoft .NET 庫。它使用多種技術來實現伺服器與客戶端間的雙向通信,伺服器可以隨時將消息推送到連接的客戶端。
它現在可在 ASP.NET Core 預發行版本中使用(譯者:根據原文的發佈時間)。我已經介紹過幾次 SignalR 了。
安裝
您將需要安裝 Microsoft.AspNetCore.SignalR.Client 和 Microsoft.AspNetCore.SignalR Nuget 預發行包。此外,您將需要 NPM(Node 包管理器)。安裝 NPM 後,您需要獲取 @aspnet/signalr-client 包,之後您需要從 node_modules@aspnet\signalr-client\dist\browser 文件夾中 獲取 signalr-client-1.0.0-alpha1-final.js 文件(版本可能不同) ,並將其放置在 wwwroot 文件夾下,以便您可以從頁面引用到它。
接下來,我們需要在使用之前在 ConfigureServices 中註冊所需的服務:
services.AddSignalR();
我們將實現一個簡單的聊天客戶端,因此將在 Configure 方法中註冊一個 ChatHub:
app.UseSignalR(routes =>
{
routes.MapHub<ChatHub>("chat");
});
註意:UseSignalR 必須在 UseMvc 之前調用!
如果你有不同的端點,可以為任意數量的 hub 執行此操作。
在您的視圖或佈局文件中,添加對 signalr-client-1.0.0-alpha1-final.js 文件的引用:
<script src="libs/signalr-client/signalr-client-1.0.0-alpha1-final.js"></script>
實現 Hub
該 hub 是一個繼承了 Hub 的類。您可在其中添加 JavaScript 可能調用到的方法。我們將實現一個 chat hub::
public class ChatHub : Hub
{
public async Task Send(string message)
{
await this.Clients.All.InvokeAsync("Send", message);
}
}
如你所見,我們有一個方法(Send),在這個例子中,它採用單個參數(message)。您不需要在廣播調用(InvokeAsync)上傳遞相同的參數,可以發送任何您想要的。
回到客戶端部分,在引用 SignalR JavaScript 文件後添加此代碼:
<script>
var transportType = signalR.TransportType.WebSockets;
//can also be ServerSentEvents or LongPolling
var logger = new signalR.ConsoleLogger(signalR.LogLevel.Information);
var chatHub = new signalR.HttpConnection(`http://${document.location.host}/chat`, { transport: transportType, logger: logger });
var chatConnection = new signalR.HubConnection(chatHub, logger);
chatConnection.onClosed = e => {
console.log('connection closed');
};
chatConnection.on('Send', (message) => {
console.log('received message');
});
chatConnection.start().catch(err => {
console.log('connection error');
});
function send(message) {
chatConnection.invoke('Send', message);
}
</script>
請註意:
- 創建指向當前 URL 的連接添加了 chat 尾碼,這與在 MapHub 中註冊的一致
- 它使用特定的傳輸進行初始化(本例中是 WebSockets),但這不是必需的,也就是說,您可以讓 SignalR 自己採用合適的方式。對於某些操作系統(如 Windows 7),您可能無法使用 WebSockets,因此您必須選擇 LongPolling 或 ServerSentEvents
- 需要通過調用 start 來初始化連接
- 有一個 Send 方法的 handler,它與 ChatHub 的 Send 方法有相同的單個參數(message)
所以,每當有人訪問此頁面並調用 JavaScript send函數時,它將調用 ChatHub 類上的 Send 方法。 該類基本上會向所有連接的客戶端(Clients.All)廣播此消息。 也可以將消息發送到特定的組:
await this.Clients.Group("groupName").InvokeAsync("Send", message);
或特定客戶端:
await this.Clients.Client("id").InvokeAsync("Send", message);
如果使用身份驗證,您可以添加一個由連接 ID 和 ClaimPrincipal 標識的用戶,如下所示:
public override Task OnConnectedAsync()
{
this.Groups.AddAsync(this.Context.ConnectionId, "groupName");
return base.OnConnectedAsync();
}
是的,OnConnectedAsync 在新用戶連接時將被調用。當有人斷開連接時,OnDisconnectedAsync 將被調用:
public override Task OnDisconnectedAsync(Exception exception)
{
return base.OnDisconnectedAsync(exception);
}
如果在斷開連接時發生一些異常,則 exception 參數將為非空值。
只有當前用戶進行身份驗證時 Context 屬性才會提供 ConnectionId 和 User 兩個屬性。ConnectionId 始終被設置為同一個用戶,不會改變。
另一個例子,假設你想通過定時器 hub 將定時器 tick 發送到所有連接的客戶端。 您可以在 Configure 方法中執行此操作:
TimerCallback callback = (x) => {
var hub = serviceProvider.GetService<IHubContext<TimerHub>>();
hub.Clients.All.InvokeAsync("Notify", DateTime.Now);
};
var timer = new Timer(callback);
timer.Change(TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(10));
我們啟動了一個 Timer,從那裡我們得到了一個定時器 hub 的引用,並使用當前時間戳調用其 Notify 方法。TimerHub 類只是這樣:
public class TimerHub : Hub
{
}
請註意,此類沒有公共方法,因為它不是由 JavaScript 調用,它僅用於從外部廣播消息(Timer 回調)。
將消息發送到 Hub
最後,還可以將消息從外部發送到 hub。當使用控制器時,您需要註入一個 IHubContext
private readonly IHubContext<ChatHub> _context;
[HttpGet("Send/{message}")]
public IActionResult Send(string message)
{
//for everyone
this._context.Clients.All.InvokeAsync("Send", message);
//for a single group
this._context.Clients.Group("groupName").InvokeAsync("Send", message);
//for a single client
this._context.Clients.Client("id").InvokeAsync("Send", message);
return this.Ok();
}
請註意,這與訪問 ChatHub 類不同,您無法簡單實現,需要通過 chat hub 的連接才行。
結論
SignalR 尚未發佈,仍可能會發生一些變化。在以後的文章中,我將更詳細地介紹 SignalR,包括其可擴展性機制和一些更高級的使用場景。敬請期待!