2018 年 7 月

第 33 卷,第 7 期

本文章是由機器翻譯。

前線最尖端 - 線上使用者、串流和其他 SignalR 好料

藉由Dino Esposito |2018 年 7 月

Dino Esposito如果您曾經使用 SignalR 的任何版本,適用於傳統的 ASP.NET 平台,您應該很熟悉中樞的概念。Signalr 中樞是可讓排列雙向遠端程序呼叫,從用戶端到伺服器和伺服器連線的用戶端相容的用戶端和伺服器應用程式的元件。

具體而言,就軟體而言中樞是繼承自系統提供的基底類別,並會公開端點,讓用戶端呼叫的類別。在概念上來說,有幾個點,與 ASP.NET 控制器相同。特別是,它是外觀,以接收用戶端呼叫和回應,並分為相對較少的相關函式。在 ASP.NET Core SignalR 集線器與控制器之間的相似處是,方式,更緊密。這是 ASP.NET Core SignalR 相關的技術最前線] 欄中,我第三篇文章,並在任一先前兩篇文章中未使用非空白中樞類別。說明關於 SignalR 中樞和它們如何實作 ASP.NET Core 中的更是本文的目的。不過,我也會談到 SignalR,特別是資料流和線上使用者數目的其他有趣的層面。

在 ASP.NET Core SignalR 中樞

中樞是透過此連線的用戶端和伺服器交換訊息的訊息管線中的進入點。中樞會公開其方法為 Url,並處理任何收到的參數,模型繫結,透過相同方式進行標準的控制器則會。一來,中樞會是專用的控制站運作超過兩個內建的通訊協定。預設的通訊協定包含 JSON 物件,但另一個二進位通訊協定可用 MessagePack 為基礎。請注意,為了支援 MessagePack,瀏覽器必須支援 XHR 層級 2。層級 2 上一步是在 2012年引進的因為這可能不是太大的問題現在,但如果您的應用程式需要支援非常舊的瀏覽器可能值得一提。可以在這裡進行快速的瀏覽器檢查: caniuse.com/#feat=xhr2

如果有任何連接的用戶端的要求 SignalR 端點時,中樞會直接叫用 SignalR 執行階段引擎。交談會高於所選的通訊協定,大部分是可能的 Websocket 中的位置。若要叫用伺服器,用戶端需要保存連接物件。Web 用戶端會取得它,如下所示:

var clockConnection = new signalR.HubConnection("/clockDemo");
clockConnection.start().then(() => {
     clockConnection.invoke("now");
  });

用戶端叫用透過 「 叫用 」 方法,在連線物件上的伺服器端點。請注意,確切的語法可能會不同,根據實際用戶端所使用的技術而定。伺服器回覆透過中樞基底類別上定義的方法,交談會高於最常 Websocket,像這樣的選擇的傳輸通訊協定中的位置:

public class ClockHub : Hub
{
  public Task Now()
   {
    var now = DateTime.UtcNow.ToShortTimeString();
    return Clients.All.SendAsync("now", now);
  }
}

請注意,您將無法監視各種使用 Fiddler 等的 HTTP 工具的呼叫。您需要類似 Chrome Developer Tools。在所有範例中我寫過有關 SignalR 我過去的資料行,不過,我一律使用空的中樞類別。

Hub 類別是官方 SignalR 外觀來接收用戶端呼叫和用戶端/伺服器通訊,因為專用的管線中進行的最快方式。透過中樞呼叫時,可以追蹤 SignalR 執行階段,並將其公開 (expose) 所有可用的資訊,透過基底的中樞類別的屬性。如此一來,SignalR 連線識別碼和呼叫,其中包括的任何宣告的已驗證的使用者的整個內容可用。

此外,透過集線器,開發人員可以處理連線與中斷連線事件。每當新的連接設定,或不,中樞的方法是回撥。如果您使用 SignalR 只做為監視遠端的長時間執行作業的方式,然後也透過一般控制站工作觸發程序和插入通知中的中樞內容。或,或者,您可以叫用中樞,並從中樞內的工作觸發程序。這是您的選擇。SignalR 的運作方式的端對端架構,用戶端與伺服器之間的橋樑。撰寫邏輯程式碼的中樞是可接受的只要工作不會太深入探索您的程式碼的多層。否則,請瀏覽控制器,是否 MVC 或 Web API,並將中樞內容。

使用集線器或控制器之間唯一的差別是當要求傳出控制器透過 SignalR 無法追蹤的連線識別碼。如果伺服器工作相關的連線識別碼,它就必須以某種方式透過 URL 傳遞。所有 form SignalR 呼叫端內容的其他資訊可以擷取透過 HTTP 要求內容的控制站。

計算使用者的線上

某些 Web 應用程式很有用,或只是吸引人的使用者,若要顯示多少個連線且目前正在使用。在新的資料流模型中,用戶端訂閱新的伺服器物件的型別通道和伺服器 — 中樞,實際上,會產生新的項目,因為它們擷取。

目前,推出時,所有連線的用戶端向該流程位元組資料流的真正是 nothing,但在未來支援此模型。請注意,將通道型別隨 preview2 不支援在舊版的組建。在先前的組建中,您必須改用可預見值,而這需要 System.Reactive.Linq NuGet 套件的參考。可預見值和新的型別通道與 IObservable 的基本型別缺乏使用網路背壓 (也就,告知用戶端不處理訊息的速度不夠快時慢的伺服器) 之間切換。[圖 3呈現為中樞的程式碼。圖 3,以往回串流 Hub 類別中樞提供三種方法來啟動、 停止和操作小時鐘。

全域變數會控制的執行中狀態的工作資料流,並開始和停止方法設定控制變數,並通知後的用戶端方法,如往常般在 SignalR hub。麻煩的部分是刻度的方法。方法名稱一致的用戶端會訂閱的資料流名稱。方法會傳回指定型別的通道物件。在範例中,其類型是簡單的字串,但它可以是任何更複雜的東西。每個引動過程,從用戶端到伺服器或伺服器到用戶端,是由一個傳送的引動過程訊息的合作對象和其他合作對象最終完成訊息攜帶結果或錯誤回應所組成。在 SignalR 串流處理案例中,相反地,另一方會回應多個訊息,每個執行資料的項目,在最終做出結論與完成訊息的通訊之前。

如此一來,用戶端最後會處理多個項目,即使之前完成訊息接收。

public class SampleHub : Hub
{
  private static int Count = 0;
  public override Task OnConnectedAsync()
  {
    Count++;
    base.OnConnectedAsync();
    Clients.All.SendAsync("updateCount", Count);
    return Task.CompletedTask;
  }
  public override Task OnDisconnectedAsync(Exception exception)
  {
    Count--;
    base.OnDisconnectedAsync(exception);
    Clients.All.SendAsync("updateCount", Count);
    return Task.CompletedTask;
  }
}

調整多個執行個體SignalR 會將所有的連線識別碼保留在記憶體中,這表示,目前的應用程式成長到多個執行個體,在廣播 (但也串流,如稍後所討論) 會受到影響,因為每個執行個體只會追蹤所有已連線的用戶端的一部分。若要避免這種情況,SignalR 支援以 Redis 為基礎的快取,可確保新的連線會自動共用執行個體之間。若要啟用 Redis,您需要 SignalR.Redis 封裝和啟動類別的 ConfigureServices 方法中 AddRedis 方法的呼叫就像這樣:

選項參數用途的 Redis 執行個體的連接字串中指定。ASP.NET Core SignalR 會從非核心版本隨附兩個重大的變更。其中一個是缺乏自動重新連線,這會影響連接/中斷連接和線上使用者的計數以程式設計方式處理。

這表示,現在每個應用程式必須處理連接/中斷連線的邏輯,並可能對找出第一次連接的使用者和重新連線,因為發生錯誤的使用者之間的差異。其他變更都支援資料流。

資料流為基礎的通道,以及目前只支援特定的資料項目,而不是未經處理的資料流。

最後,我瀏覽的 SignalR 缺少一個的多個片段,我將在未來的專欄探討: 驗證使用者和群組。Dino Esposito 有 20 個以上的書籍和 1,000 的文章,他 25 年職涯中撰寫。作者的 「 休假中斷,「 電影樣式節目,Esposito 正在將擁有更為環保的世界的軟體撰寫成在 BaxEnergy 數位策略家。在 Twitter 上關注與他連絡: @despos。

感謝下列 Microsoft 專家檢閱這篇文章:

運算式 描述
Clients.All 通知會廣播到所有已連線的用戶端,不論所使用的技術 (web.NET,.NET Core,Xamarin)。
Clients.Client(connectionId) 以獨佔方式來接聽指定的連接透過用戶端會傳送通知。
Clients.User(userId) 通知會傳送至所有用戶端,其已驗證的使用者符合提供的使用者名稱。
Clients.Groups(group) 通知會傳送至所有屬於指定之群組的用戶端。

 

群組是相關的用戶端共同蒐集的名稱集合。SignalR 中的群組進行思考的更自然的方式是聊天室。會建立一個群組,只需以程式設計方式新增至群組名稱已給定的 [連線識別碼。方法如下:

hub.Groups.AddAsync(connectionId, nameOfGroup);

連線的用戶端會收到他們透過回呼的資料。這是只有最常見的技巧。在 ASP.NET Core SignalR,您也可以使用資料流。

資料流

最有趣的新 SignalR 層面,可能是支援資料流。串流處理類似於廣播,但它會遵循稍有不同的模型,而且基本上是稍微不同的方式達到相同的廣播型通訊。使用 SignalR 串流時,中樞仍然需要輪詢,或接聽的資料,才能傳送回資料流。在傳統的廣播中,伺服器會告訴用戶端方法,新的資料可用時。

在新的資料流模型中,用戶端訂閱新的伺服器物件的型別通道和伺服器 — 中樞,實際上,會產生新的項目,因為它們擷取。目前,推出時,所有連線的用戶端向該流程位元組資料流的真正是 nothing,但在未來支援此模型。請注意,將通道型別隨 preview2 不支援在舊版的組建。在先前的組建中,您必須改用可預見值,而這需要 System.Reactive.Linq NuGet 套件的參考。可預見值和新的型別通道與 IObservable 的基本型別缺乏使用網路背壓 (也就,告知用戶端不處理訊息的速度不夠快時慢的伺服器) 之間切換。

[圖 3呈現為中樞的程式碼。

圖 3,以往回串流 Hub 類別

public class ClockHub : Hub
{
  private static bool _clockRunning = false;
  public void Start()
  {
    _clockRunning = true;
    Clients.All.SendAsync("clockStarted");
  }
  public void Stop()
  {
    _clockRunning = false;
    Clients.All.SendAsync("clockStopped");
  }
  public ChannelReader<string> Tick()
  {    var channel = Channel.CreateUnbounded<string>();
    Task.Run(async() => {
      while(_clockRunning)
      {
        var time = DateTime.UtcNow.ToString("HH:mm:ss");
        await channel.Writer.WriteAsync(time);
        await Task.Delay(1000);
      }
      channel.Writer.TryComplete();    });
  }
}

中樞提供三種方法來啟動、 停止和操作小時鐘。全域變數會控制的執行中狀態的工作資料流,並開始和停止方法設定控制變數,並通知後的用戶端方法,如往常般在 SignalR hub。麻煩的部分是刻度的方法。方法名稱一致的用戶端會訂閱的資料流名稱。方法會傳回指定型別的通道物件。在範例中,其類型是簡單的字串,但它可以是任何更複雜的東西。

每個引動過程,從用戶端到伺服器或伺服器到用戶端,是由一個傳送的引動過程訊息的合作對象和其他合作對象最終完成訊息攜帶結果或錯誤回應所組成。在 SignalR 串流處理案例中,相反地,另一方會回應多個訊息,每個執行資料的項目,在最終做出結論與完成訊息的通訊之前。如此一來,用戶端最後會處理多個項目,即使之前完成訊息接收。

調整多個執行個體

SignalR 會將所有的連線識別碼保留在記憶體中,這表示,目前的應用程式成長到多個執行個體,在廣播 (但也串流,如稍後所討論) 會受到影響,因為每個執行個體只會追蹤所有已連線的用戶端的一部分。若要避免這種情況,SignalR 支援以 Redis 為基礎的快取,可確保新的連線會自動共用執行個體之間。若要啟用 Redis,您需要 SignalR.Redis 封裝和啟動類別的 ConfigureServices 方法中 AddRedis 方法的呼叫就像這樣:

services.AddSignalR()
        .AddRedis("connection string");

選項參數用途的 Redis 執行個體的連接字串中指定。

總結

ASP.NET Core SignalR 會從非核心版本隨附兩個重大的變更。其中一個是缺乏自動重新連線,這會影響連接/中斷連接和線上使用者的計數以程式設計方式處理。這表示,現在每個應用程式必須處理連接/中斷連線的邏輯,並可能對找出第一次連接的使用者和重新連線,因為發生錯誤的使用者之間的差異。其他變更都支援資料流。資料流為基礎的通道,以及目前只支援特定的資料項目,而不是未經處理的資料流。

最後,我瀏覽的 SignalR 缺少一個的多個片段,我將在未來的專欄探討: 驗證使用者和群組。


Dino Esposito有 20 個以上的書籍和 1,000 的文章,他 25 年職涯中撰寫。作者的 「 休假中斷,「 電影樣式節目,Esposito 正在將擁有更為環保的世界的軟體撰寫成在 BaxEnergy 數位策略家。在 Twitter 上關注與他連絡: @despos

感謝下列 Microsoft 專家檢閱這篇文章:Andrew Stanton-nurse


MSDN Magazine 論壇中的這篇文章的討論