在 ASP.NET Core 中使用 SignalR


https://weblogs.asp.net/ricardoperes/signalr-in-asp-net-core
作者:Ricardo Peres
譯者:oopsguy.com

介紹

SignalR 是一個用於實現實時功能的 Microsoft .NET 庫。它使用了多種技術來實現服務器與客戶端間的雙向通信,服務器可以隨時將消息推送到連接的客戶端。

現在你可以在 ASP.NET Core 預發行版本中體驗它(譯者:根據原文的發布時間)。我已經介紹過幾次 SignalR 了。

安裝

你將需要安裝 Microsoft.AspNetCore.SignalR.ClientMicrosoft.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>

請注意:

  1. 創建指向當前 URL 的連接后,鏈接添加了 chat 后綴,這與在 MapHub 中注冊的一致
  2. 它使用特定的傳輸方式進行初始化(本例中是 WebSockets),但這不是必需的,也就是說,你可以讓 SignalR 自己采用合適的方式。對於某些操作系統(如 Windows 7),比如你可能無法使用 WebSockets,因此你必須選擇 LongPollingServerSentEvents
  3. 需要通過調用 start 來初始化連接
  4. handler 的 Send 方法與 ChatHubSend 方法有相同的單個參數(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 屬性才會提供 ConnectionIdUser 兩個屬性。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 實例,你可以在里面發送消息到 hub,然后將其廣播:

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,包括其可擴展性機制和一些更高級的使用場景。敬請期待!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM