私は、サーバー(MVC Core Webアプリケーション)で何らかのイベントが発生したときにWebソケットプロトコルを使用してクライアント(Webブラウザ)に通知するソリューションを開発中です。私はMicrosoft.AspNetCore.WebSocketsナゲットを使用します。このビューは、ソケット要求をロードされている MVCコア、Webソケットとスレッド
$(function() {
var socket = new WebSocket("ws://localhost:61019/data/openSocket");
socket.onopen = function() {
$(".socket-status").css("color", "green");
}
socket.onmessage = function (message) {
$("body").append(document.createTextNode(message.data));
}
socket.onclose = function() {
$(".socket-status").css("color", "red");
}
});
はすぐにMVC Coreアプリケーションに送信されます。
は、ここに私のクライアント側のコードです。コントローラーアクションは次のとおりです。
[Route("data")]
public class DataController : Controller
{
[Route("openSocket")]
[HttpGet]
public ActionResult OpenSocket()
{
if (HttpContext.WebSockets.IsWebSocketRequest)
{
WebSocket socket = HttpContext.WebSockets.AcceptWebSocketAsync().Result;
if (socket != null && socket.State == WebSocketState.Open)
{
while (!HttpContext.RequestAborted.IsCancellationRequested)
{
var response = string.Format("Hello! Time {0}", System.DateTime.Now.ToString());
var bytes = System.Text.Encoding.UTF8.GetBytes(response);
Task.Run(() => socket.SendAsync(new System.ArraySegment<byte>(bytes),
WebSocketMessageType.Text, true, CancellationToken.None));
Thread.Sleep(3000);
}
}
}
return new StatusCodeResult(101);
}
}
このコードは非常にうまくいきます。ここのWebSocketは送信専用に使用され、何も受信しません。ただし、問題は、キャンセル要求が検出されるまで、WhileループがDataControllerスレッドを保持し続けることです。
ここでWebソケットはHttpContextオブジェクトにバインドされています。 WebリクエストのHttpContextが破棄されるとすぐに、ソケット接続は直ちに閉じられます。
質問1:コントローラスレッド外でソケットを保存できる方法はありますか? メインアプリケーションスレッドで動作しているMVCコアスタートアップクラスに存在するシングルトンに入れようとしました。 whileループでコントローラスレッドを保持し続けるのではなく、ソケットを開いたままにしたり、メインアプリケーションスレッド内から接続を再確立する方法はありますか? ソケット接続用のコントローラスレッドを開いたままにしておくことがOKであるとみなされても、OpenSocketのwhileループの中に入れる良いコードはないと思います。コントローラーで手動リセットイベントを実行し、OpenSocketアクション内のwhileループ内でそのイベントがセットされるのを待つのはどう思いますか?
質問2:MVCでHttpContextオブジェクトとWebSocketオブジェクトを分離できない場合、ソケット接続の再利用を実現するために、他にどのような代替技術や開発パターンを利用できますか? SignalRやそれに類するライブラリがHttpContextから独立したソケットを持つことを可能にするいくつかのコードを持っていると誰かが考えているなら、いくつかのコード例を教えてください。 MVCに独立したソケット通信を処理する機能がない場合、この特定のシナリオでMVCに代わるより優れた方法があると考える人は、例を挙げてください。純粋なASP.NETまたはWeb APIに切り替えるのは気にしません。
質問3:明示的なタイムアウトまたはユーザーによるキャンセル要求まで、ソケット接続を有効にしておくか、再接続できるようにする必要があります。考えられるのは、確立されたソケットからデータを送信するトリガーとなる独立したイベントがサーバー上で発生するということです。 Webソケット以外のいくつかの技術(HTML/2やストリーミングなど)がこのシナリオでもっと役立つと思われる場合は、使用するパターンやフレームワークを記述できますか?
P.S.可能な解決策は、毎秒AJAX要求を送信してサーバーに新しいデータがあるかどうかを尋ねることです。これが最後の手段です。
'SignalR'は非常に有望ですが、多くのことを知らないのでコードを提供することはできません。 – VMAtm