おーみんブログ

C#, ASP.NET Core, Unityが大好きです。

ASP.NET Core + SignalRの公式チュートリアルをやってみた!

はじめに

現在双方向通信などの勉強をしておりgRPCを主に調査していたのですが、以前の現場の上司にSignalRについて教えてもらったので公式チュートリアルをやってみました!
SignalRについては名前はよく聞いていたのですが、なかなか手を付ける機会がなく...しかしながらこの機会にちゃんと学習していこうと思います!

記事の内容は以下の公式チュートリアルに沿って学習した備忘録的な感じになっているので詳細はそちらを確認したほうが良さそうです。

ASP.NET Core SignalR の概要 | Microsoft Docs

Webアプリプロジェクトの作成

公式チュートリアルに沿って新しいプロジェクトクトの作成 > ASP.NET Core Webアプリを選択し、新規プロジェクトを作成します。

SignalRクライアントライブラリを追加

デフォルトではJavaScript用のSignalRライブラリは入っていないのでunpkgからインストールします。

SignalRプロジェクトを右クリック > 追加 > クライアント側のライブラリをクリックします。
pic2.png

以下のようにダイアログが表示されるのでプロバイダーをunpkg、ライブラリを@microsoft/signalr@latestとし、特定のファイルの選択を選択してsignalr.jssignalr.min.jsにチェックを入れます。
以下のように設定できたらインストールをクリックします。
pic.png

SignalRハブの作成

Hubはクライアント側とサーバ側を繋げるパイプラインの役割を担います。
接続しているクライアント情報、グループ情報等を管理するHubクラスを継承し、以下のようにコードを作成します。

using Microsoft.AspNetCore.SignalR;
using System.Threading.Tasks;

namespace WebApplication1.Hubs
{
    public class ChatHub : Hub
    {
        public async Task SendMessage(string user, string message)
        {
            //ハブに接続しているユーザ全てにメッセージを送信する。
            await Clients.All.SendAsync("ReceiveMessage", user, message);
        }
    }
}

SignalRサーバの構成

Startupクラスへ以下のようにそれぞれ追加します。

public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages();
    services.AddSignalR(); //<--追加
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    //省略

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
        //Hubへのエンドポイント
        endpoints.MapHub<ChatHub>("/chatHub"); //<--追加
    });
}

SignalRクライアントコードの追加

@page
    <div class="container">
        <div class="row">&nbsp;</div>
        <div class="row">
            <div class="col-2">User</div>
            <div class="col-4"><input type="text" id="userInput" /></div>
        </div>
        <div class="row">
            <div class="col-2">Message</div>
            <div class="col-4"><input type="text" id="messageInput" /></div>
        </div>
        <div class="row">&nbsp;</div>
        <div class="row">
            <div class="col-6">
                <input type="button" id="sendButton" value="Send Message" />
            </div>
        </div>
    </div>
    <div class="row">
        <div class="col-12">
            <hr />
        </div>
    </div>
    <div class="row">
        <div class="col-6">
            <ul id="messagesList"></ul>
        </div>
    </div>
    <script src="~/js/signalr/dist/browser/signalr.js"></script>
    <script src="~/js/chat.js"></script>
"use strict";

var connection = new signalR.HubConnectionBuilder().withUrl("/chatHub").build();

// 上記のコネクションが成立するまでは送信ボタンを押せないようにします。
document.getElementById("sendButton").disabled = true;

// Hub側から"ReceiveMessage"が呼び出された場合にこちらで登録した操作が動きます。
connection.on("ReceiveMessage", function (user, message) {
    var li = document.createElement("li");
    document.getElementById("messagesList").appendChild(li);
    li.textContent = `${user} says ${message}`;
});

connection.start().then(function () {
    document.getElementById("sendButton").disabled = false;
}).catch(function (err) {
    return console.error(err.toString());
});

document.getElementById("sendButton").addEventListener("click", function (event) {
    var user = document.getElementById("userInput").value;
    var message = document.getElementById("messageInput").value;
    // Hub側のSendMessageメソッドを呼び出します。userとmessageはSendMessageメソッドの引数になります。
    connection.invoke("SendMessage", user, message).catch(function (err) {
        return console.error(err.toString());
    });
    event.preventDefault();
});

デバッグ実行

実際に実行すると、以下のようにチャットアプリのような動きを確認することができます。
異なるタブから実行しても片方のタブの画面でチャット結果が表示されます。
pic1.png

おわりに

こんな簡単にブラウザ間での双方向ストリーミングが出来るなんて!!とても良いですね!
双方向ストリーミングといえば最近はgRPCをよく聞きますが、そちらの勉強と並行してこちらも今後勉強していこうと思います!