多くの苦労と簡単な方法を見つけられなかった後、私は将来誰かのために以下の方法を見つけました。
シナリオ: 1. Web ファーム: 外部ユーザー向けの Web ページをホストする 2. バックエンド プロセス: WebApi、SharePoint、Windows サービスなどの組み合わせです。
Web ページからのユーザーが何らかのリクエストを送信し、戻り値として一意の ID を取得します。内部で要求を受信すると、処理のために TopicClient を使用してその要求を Service Bus のキューに入れます。
SubscriptionClient を使用して Service Bus 上のメッセージを監視する Windows サービスのプールがあり、そのメッセージを処理します。5 秒から 30 秒、場合によってはそれ以上かかるプロセスの完了時。Web ページで待機している場合、または完了通知を待機している場合は、ジョブが完了したことをクライアントに通知する必要があります。
このストーリーでは、SignalR を使用してジョブの完了通知をクライアントにプッシュしています。
今私の以前の問題は、ジョブが完了したことをWindowsサービスからWebアプリケーションに通知する方法です。リクエストを送信したクライアントに通知を送信します。
1 つの方法は、別のハブを Web アプリケーション内で内部的にホストすることです。Windows サービスはクライアントとして機能し、Web アプリケーションがホストするハブを呼び出します。そのハブ メソッドでは、外部向けのハブ メソッドを呼び出して、要求を送信した特定のクライアントにメッセージを伝達します。シングル ユーザー グループを使用します。
また、サービス バスをバックプレーンとして登録しているため、他のサーバーに伝達され、適切なクライアントが通知を受け取ります。したがって、これは理想的なソリューションであり、ほとんどの場合に機能するはずです。
上記のアプローチでは、Windows 認証がないため、Windows サービスが Web クライアントに接続する方法という 1 つの制限がありますが、ADFS では openid ベースの認証があります。このような場合、Web アプリケーションは、Windows サービスが通信するために別のユーザー ID またはパスワードを提供するか、Windows サービスのサービス アカウントのハブに対しても Windows 認証を許可する特別なコードを必要としました。
私は、サーバー間通信と追加のセキュリティの管理との間のこの希望をすべて取り除く方法を試していました。
そのため、SignalR の内部を見つけるのに一晩かかりましたが、簡単に以下を行いました。しかし、それは機能します:
アプローチは、メッセージを ServiceBus バックプレーンに直接送信することです。すべての Web サーバーは既に ServiceBus バックプレーンに接続されているため、メッセージを受信します。
残念ながら、SignalR はメッセージを直接バックプレーンに送信するメカニズムを提供していません。私はそれがpub / subモデルにあると思うので、誰かがシステムをハッキングすることを望んでいません:)。またはそのパターンの違反ですが、私の場合は役割とセキュリティが異なるため、理にかなっています。コードを次のように単純化しました。
- 以下と同じ方法で、私のコードで ServiceBusMessageBus インスタンスを作成します: 別のインスタンスを作成し、Windows サービスの存続期間まで保存したので、毎回インスタンスを作成しません:
ServiceBusMessageBus serviceBusBackplane = new ServiceBusMessageBus(new DefaultDependencyResolver(), new ServiceBusScaleoutConfiguration(connectionString, appName));
ClientHubInvocation オブジェクトを作成する: これは、バックプレーン ベースのメッセージ ブロードキャスト時に SignalR インフラストラクチャで実際に作成されるメッセージです。
ClientHubInvocation hubData = new ClientHubInvocation
{
Args = new object[] { msg },
Hub = "JobStatusHub",
Method = "onJobStatus",
State = null,
};
はい、ServiceBusMessageBus.Publish によって受け入れられるメッセージ オブジェクトを作成します。これは、基本クラス ScaleoutMessageBus.Publish で実際に呼び出されるメソッドです。このクラスは、実際には、他のサーバー ノード上のトピックおよび他のサブスクライバーにメッセージを送信する役割を果たします。それを直接使用してみませんか。Message オブジェクトを作成するには、次のコードが必要です。
Message backplaneMessage = new Message( sourceId, "hg-JobStatusHub." + name, new ArraySegment(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(hubData))));
上記の 2 番目のパラメーターは興味深いものです。すべてのクライアントに公開する場合、構文は "h-" です。私の場合、特定のグループ ユーザーなので、構文は "hg-.. ここでコードを確認できます: https ://github.com/SignalR/SignalR/blob/bc9412bcab0f5ef097c7dc919e3ea1b37fc8718c/src/Microsoft.AspNet.SignalR.Core/Infrastructure/PrefixHelper.cs
- 以下のように、メッセージをバックプレーンに直接発行します。
serviceBusBackplane.Publish (backplaneMessage) を待機します。
この PrefixHelper クラスが公開されていることを願っています。
覚えておいてください: これは推奨される方法ではなく、SignalR の将来のアップグレードから隔離されません。しかし、要約すると、これは機能します。SignalR チームが、メッセージをバックプレーンに直接送信するためのすぐに使用できるメカニズムを提供してくれることを願っています。
ありがとう