May 2018

Volume 33 Number 5

Cutting Edge - ASP.NET Core SignalR の内側

によってDino Esposito

Dino EspositoSignalR は、ASP.NET Core プラットフォーム、およびその時間の長い待機の 1 つに、直前に追加します。のみ SignalR ボード上で開始できることお本当に ASP.NET Core アプリケーションのすべての種類のピーク時の準備ができて見て音声 dare を取得します。重大な Web アプリケーションが現在ないはなく実行できます非同期通知およびリアルタイムの機能のいくつかの形式です。

ASP.NET からわかって SignalR では、完全に再作成し、ASP.NET Core ライブラリのファミリで今すぐに常駐します。過去 1 か月のコラム (msdn.com/magazine/mt846469)、機能のクイック ツアーと新規の ASP.NET Core SignalR の機能を提供しました。この列でありますについて詳しく内部の機構です。

SignalR 双方向、双方向のリモート プロシージャ コール (RPC) の抽象化レイヤーは、さまざまなトランスポート プロトコル上で動作します。ホストにとらわれないおよび HTTP に限定されません。最新のバージョンでは、バイナリ データといないだけ JSON ベースのメッセージを転送にできます。SignalR ASP.NET または ASP.NET Core のいずれかを構成する場合は、トランスポート プロトコルとメッセージ プロトコルを選択できます。明示的な選択しない場合は、トランスポート プロトコルが自動的に選択し、ほとんどのことが判明 Websocket です。これに対し、メッセージ プロトコルは、JSON に基づいています。場合、クライアントの動作を見てみましょう — たとえば、Web クライアント-サーバーのエンドポイントとの接続を設定します。次のコードでは、接続を開始します。

var progressConnection = new signalR.HubConnection("/progressDemo");
progressConnection.start();

Fiddler などのツールでは、このコードによって生成された Web トラフィックを監視する場合、2 つの HTTP 要求が送信されることが表示されます。図 1メッセージ交換のブートス トラップ最初の要求の詳細を表示します。

初期のスターター要求の詳細
図 1 の初期のスターター要求情報

最初の要求が続けてスタートアップ クラスで指定された SignalR のルートを対象とする HTTP POST、/セグメントをネゴシエートします。次のコードでは、SignalR のルートを定義する方法を示します。

app.UseSignalR(routes =>
{
  routes.MapHub<ProgressHub>("/progressDemo");
});

ルートに基づき、最初の呼び出しが、対象 URL: progressdemo/ネゴシエートします。

SignalR のプレビュー バージョンでは、同じ用途のオプション動詞が使用されたに注意してください。SignalR のサーバーのエンドポイントは、次のように構成されている JSON オブジェクトを返します。

{
  "connectionId" : "b6668ac0-1083-499f-870a-2a5376bf5047",
  "availableTransports" : [
    "WebSockets", "ServerSentEvents", "LongPolling"
  ]
}

次の 2 つが JSON の応答に含まれることがわかります。 だけ確立された接続、および使用可能なトランスポート プロトコルの一覧の一意の ID。サンプル コードでは、Websocket、ServerSentEvents および LongPolling を使用できること、クライアントとサーバーの構成を示します。次の動作は、クライアントが実際に選択したトランスポートによって異なります。

SignalR では、可能な場合は Websocket を使用する傾向があります。ServerSentEvents がチェックされと後にフォールバック LongPolling します。Websocket を使用する場合は前に、と同じ URL に HTTP GET 要求が配置されます。この時間要求も追加の接続 ID をクエリ文字列パラメーターとしてします。GET 要求には、実際には、プロトコルのアップグレード要求はします。具体的には、プロトコルのアップグレードは、標準 HTTP 要求 (GET ができる場合もあります投稿) を 2 つのアド ホック ヘッダーです。1 つが、Connection ヘッダー。 アップグレードに設定する必要があります。もう 1 つは、アップグレードで、必要なプロトコルの名前に設定する必要があります: この場合は Websocket です。サーバー プロトコルのアップグレードが受け入れられると、HTTP 101 切り替えプロトコル応答が返されます (のように図 1)。

トランスポート プロトコル

SignalR には、さまざまなトランスポート プロトコルを使用できます。クライアントは、特定のプロトコルを介して行わへの接続を強制できますが、既定では、プロトコルが自動的に決定されます。特定のトランスポートを要求するには、だけで、JavaScript コード (またはクライアント コード以外の Web クライアントが使用されている場合) に余分なパラメーターを追加します。以下に例を示します。

var progressConnection = new signalR.HubConnection(
  "/progressDemo",
  {transport : signalR.TransportType.WebSocket});

直接名の代わりに配列を渡すことによってできますを制限することを選択、いくつかの指定したプロトコルのいずれかに注意してください。もちろん、トランスポート プロトコルは、いくつかの点で異なります。図 2各プロトコルの主な特徴を一覧表示します。

図 2 は、トランスポート プロトコルをサポートします。

プロトコル 説明
WebSockets クライアントとサーバー間の一対一の接続に基づいています。クライアントとサーバーの両方は、データのフローは次の双方向ように共有パイプで作成します。プロトコルでは、すべての場所で使用することはできません、ブラウザーとの接続に使用されているサーバーによって制限されます。クライアントでは、最新のブラウザーが必要です。一般的なあらゆるブラウザーの最新バージョン通常動作、Internet Explorer バージョン 10 より前の例外。サーバー側、IIS または HttpSysServer を使用して、クライアントで Windows 8 以降が必要です。
ServerSentEvents EventSource のオブジェクトがサーバー上でアクティブに基づいています。このオブジェクトは、クライアントにサーバーを接続するパイプを表します。接続が確立されるは、普通の AJAX 呼び出しでのみ、クライアントが通信するときに、サーバーは継続的にイベントを送信できます。プロトコルは、Netscape の初期の頃に戻る日付し、Internet Explorer または Edge ブラウザーではサポートされていません。
LongPolling プロトコルは、将来の応答に使用するサーバーとの接続を開くことによって機能します。接続は保留中のまま、応答が送信されるか、要求がタイムアウトするまでです。いずれの場合、接続が閉じられると、クライアントすぐに再確立がポーリングが継続的なは、トラフィックは必ずしも必要では新機能に制限されるようにします。このプロトコルは、すべてのブラウザーのすべてのバージョンを連携して、フォールバック ソリューションと見なされます。

Web クライアントとサーバー間の通信がクロス ドメインの場合は、サーバーは、CORS が有効なである必要があります。この例では、任意の使用可能なプロトコル (JSONP が ASP.NET Core SignalR でサポートされていないことに注意してください) を使用できます。

public void ConfigureServices(IServiceCollection services)
{
  services.AddCors();
}

ブラウザーでは、ASP.NET Core SignalR の AJAX と Websocket の呼び出しに Origin ヘッダーを追加します。さらに、SignalR アプリケーションをブラウザーが要求を許可するように構成されている CORS ミドルウェアにする必要があります。

メッセージのプロトコル

常にシリアル化された asp.net SignalR では、テキスト ベースの JSON 形式を使用してメッセージを交換します。最新の ASP.NET Core SignalR MessagePack 形式に基づくバイナリ メッセージ プロトコルを追加します。このバイナリのシリアル化形式を使用して、JSON はよう、言語に依存しない方法でデータを交換できます。

MessagePack 両方よりコンパクトなかつ高速に、JSON よりも転送は、さらに多くの機能パケット サイズを圧縮バイナリ JSON (BSON) よりも-JSON の MongoDB 最適化フレーバー。MessagePack に小さい整数と NULL 値の両方に、1 バイトだけのデータが消費されます。比較して、JSON null 値は、4 バイトを消費します。プロトコルに関する詳細については、チェック アウトmsgpack.orgです。

使用 MessagePack ASP.NET Core SignalR Web クライアントから、だけ追加する 1 つのパラメーター、接続を設定する JavaScript コードを次のように。

var protocol = new signalR.protocols.msgpack.MessagePackHubProtocol();
var progressConnection = new signalR.HubConnection(
  "/progressDemo",
  {
    transport : signalR.TransportType.WebSocket,
    protocol : protocol
  }
);

クライアントの場合、Web MessagePack を使用したい、するも含める必要がある @aspnet/signalr NPM パッケージ内にある別の JavaScript ファイル (signalr msgpackprotocol.min.js) に注意してください。MessagePack も必要です、ASP.NET Core サーバーを構成するには、次のようにします。

public void ConfigureServices(IServiceCollection services)
{
  // SignalR already configured. Just add this:
  services.AddMessagePackProtocol();
}

以外の Web クライアントを使用する場合に、MessagePack を有効にするために必要なクライアント アプリケーションで余分な呼び出しです。具体的には、WithMessagePackProtocol が HubConnectionBuilder クラスで定義された拡張メソッドへの呼び出しを配置します。

以外の Web クライアント

.NET 標準の仕様の最も注目すべき側面は、API の互換性が存在する限り、同じ内のライブラリからのさまざまなクライアント アプリケーションを利用できます。.NET Standard 2.0 に基づく、ASP.NET Core SignalR クライアント ライブラリは、互換性のあるプラットフォームでは、Microsoft .NET Framework 4.6.1 などのさまざまなコンパイルされたクライアント アプリケーション内から使用できますと、それ以降。つまり、たとえば、4.6 では ASP.NET Core SignalR ハブのサービスを利用できる問題なくより新しい .NET Framework のバージョンに対してコンパイルされた Windows フォーム アプリケーションです。

念頭に、過去 1 か月の列に説明されている時間のかかるタスクを起動する方法を説明し、新しい Windows フォーム アプリケーション内部から監視してみましょう。Microsoft.AspNetCore.SignalR.Client とその依存関係をという名前の NuGet パッケージを参照、スケルトン アプリケーションを作成した後、作業を開始する次のようにします。

private static HubConnection _connection;
private async void Form1_Load(object sender, EventArgs e)
{
  _connection = new HubConnectionBuilder()
    .WithUrl("http://localhost:60000/progressdemo")
    .Build();
  await _connection.StartAsync();
}

フォームが読み込まれた、指定された SignalR エンドポイントとの接続を確立するときに、コードが実行されます。MessagePack プロトコルを使用してシリアル化を交換するデータの場合は、よう接続ビルダー オブジェクトの構成コードに 1 行を追加します。

private async void Form1_Load(object sender, EventArgs e)
{
  _connection = new HubConnectionBuilder()
    .WithUrl("http://localhost:60000/progressdemo")
    .WithMessagePackProtocol()
    .Build();
  await _connection.StartAsync();
}

受信した接続オブジェクトは、ASP.NET Core SignalR エンドポイントからの通知が返されると、UI の更新を担当するクライアント側のハンドラーでさらに構成する必要があります。そのコードを次に示します。

_connection.On<int>("updateProgressBar", (perc) =>
{
  this.Invoke(
    (Action) (() => label1.Text = String.Format("{0}%", perc))
});

サンプル コードで updateProgressBar 通知を受信すると、テキスト ラベルが現在行われた作業の割合を表す受信した値で更新されます。必要とサーバー側の SignalR の対応する公開同数のハンドラーをすることができます。図 3 Windows フォーム クライアントは消費する月の最後の列の SignalR バックエンドの完全、書き換えを示しています。

図 3 書き換えられた SignalR バックエンド

_connection.On("initProgressBar", () =>
{
  // Run on the UI thread
  Invoke((Action)(() => label1.Text = "0%"));
});
_connection.On<int>("updateProgressBar", (perc) =>
{
  // Run on the UI thread
  Invoke((Action) (() => label1.Text = String.Format("{0}%", perc)));
});
_connection.On("clearProgressBar", () =>
{
  // Run on the UI thread
  Invoke((Action)(() =>
  {
    label1.Text = "100%";
    button1.Enabled = true;
  }));
});
await _connection.StartAsync();

いくつかの障害もスムーズ Web 以外の SignalR クライアントを作成するときに注意してください。最初に、クライアント ハンドラーする完全に構成しなければ、接続の開始時にします。具体的には、つまり StartAsync への呼び出しをすべて実行する、due < T > のメソッド呼び出しが行われました。

次に、サーバー側を実行しないことに注意してください: 時間がかかる可能性があります: SignalR が同じ Windows UI スレッドに通知する操作。ですが、クライアント アプリケーションが応答しなくなります。問題を回避するには、次に示す別のスレッドで、サーバー側の操作を起動する必要があります。

private void button1_Click(object sender, EventArgs e)
{
  Task.Run(() =>
  {
    var client = new WebClient();
    client.UploadString("http://localhost:60000/task/lengthy);
  });
}

その後、サーバー側の SignalR ハブに戻る通知する、due 変更必要がある情報を伝えるメイン UI スレッドにことが行われる前にします。これを実現するには、クライアントのハンドラーで Invoke メソッドを使用しています。Invoke メソッドは、デリゲートを取得し、次に示すように、UI スレッドで実行します。

Invoke((Action)((perc) =>
  {
    label1.Text = String.Format("{0}%", perc);
  }));

図 4のラベルがサーバー側の操作がすべて進歩するにつれてを段階的に更新実行中、Windows フォーム アプリケーションのサンプルを示します。

ASP.NET Core SignalR ハブによって更新された Windows フォーム クライアント アプリケーション
図 4、Windows フォーム クライアント アプリケーションが ASP.NET Core SignalR ハブによって更新されました

Windows フォーム アプリケーションはサポートされているアプローチのいずれかから通知を受信できる: ブロードキャスト、直接接続、グループ、1 人のユーザーおよびストリーミングします。詳しくは今後のコラムでがあります。

まとめ

ASP.NET Core SignalR は、Websocket、ServerSentEvents LongPolling など、以前の ASP.NET バージョンと同じトランスポート プロトコルをサポートします。さらに、標準の JSON 形式に加え、バイナリ メッセージ プロトコルをサポートします。

その先行処理と同様に、さまざまなクライアントのさまざまなから ASP.NET Core SignalR を呼び出すことができます: 昔ながらの Windows フォーム アプリケーションを含むです。広範な互換性を実現するために、キーとは、.NET 標準 2.0 仕様のサポートです。既に見たよう、資料に、クライアントが、.NET Core アプリケーションがない場合は、最新の規格と互換性がある .NET Framework のバージョンにコンパイルする必要があります。必要な最小バージョンは、.NET Framework 4.6.1 です。

アーティクルのソース コードをチェック アウトを必ずbit.ly/2FxCKTsです。


Dino Esposito は、25 年におよぶキャリアの中で、20 冊以上の書籍と 1000 本を超える記事を執筆してきました。劇形式の作品『The Sabbatical Break』の著者である Esposito は、BaxEnergy のデジタル ストラテジストとして、より良い世界を構築するためにソフトウェアの記述に取り組んでいます。彼には Twitter (@despos、英語) から連絡できます。

この記事のレビューに協力してくれた Microsoft の専門家 Andrew Stanton-Nurse に心より感謝いたします。


この記事について MSDN マガジン フォーラムで議論する