プログラムを中心とした個人的なメモ用のブログです。 タイトルは迷走中。
内容の保証はできませんのであしからずご了承ください。

2018/01/22

ASP.NET Core で SignalR を使用する

update2018/03/28 event_note2018/01/22 2:53

ASP.NET Core で WebSocket を使おうと思ったら SignalR Core というものがあるのを知ったので、試してみました。

尚、WebSocket は昔に Node.js と Socket.IO を使ってみたことがあるのですが、SignalR は初めて触ります。

環境

  • Visual Studio 2017
  • ASP.NET Core 2.0

ASP.NET Core 2.0 の MVC テンプレートプロジェクトをベースとします。

サーバーサイドの実装

SignalR Core のインストール

NuGet パッケージマネージャーコンソールで以下のコマンドでインストールします。
(現在は alpha 版なので、-pre をつけてインストールする必要があります。)

PM> Install-Package Microsoft.AspNetCore.SignalR -pre

Hub クラスの作成

SignalR ではPersistent Connection と Hub という2つの通信モデルがあるようです。

今回は Hub を使用します。

SignalR.Hub を継承したクラスを作成します。

using Microsoft.AspNetCore.SignalR;

// 中略

public class SignalRTest : Hub
{
    public Task Send(string data)
    {
        return Clients.All.InvokeAsync("AddMessage", data);
    }
}

これで API が RPC として実装され、外部から Send メソッドが使用可能となります。

Startup.cs の変更

SignalR を使用するための準備として、Startup クラスの ConfigureServices メソッドに AddSignalR を追加します。

public void ConfigureServices(IServiceCollection services)
{
    services.AddSignalR();// <-- SignalR
    services.AddMvc();
}

また、Startup クラスの Configure メソッドに UseSignalR を以下のように追加します。

app.UseSignalR(routes =>  // <-- SignalR
{
    routes.MapHub<SignalRTest>(nameof(SignalRTest));
});

ここまで実装した状態でプログラムを実行し、http://localhost:xxxxx/SignalR を開いたときに Connection ID required と表示されれば正常です。

クライアントサイドの実装

SignalR の JavaScript Client を使用します。

SignalR Client のインストール

ASP.NET Core では SignalR の JavaScript 用クライアントも新しくなっているようです。

ASP.NET Core ではフロントエンドのパッケージ管理は Bower で管理されていましたが、現在では Bower は非推奨となっているので、この新しい SignalR Client も Bower では提供されていないようです。
なので、上記のサイトに書いてある通り、npm でインストールします。

npm install @aspnet/signalr-client

インストールが完了したら、signalr-client.js をプロジェクト配下の wwwroot/js にコピーします。
尚、現在ではまだ alpha 版なので、ファイル名は signalr-client-1.0.0-alpha2-final.js のようになっています。

View の追加

ASP.NET Core の MVC テンプレートプロジェクトに対して、Views/Home/SignalR.cshtml というファイルを作成しました。

Script の読み込み

従来の SignalR では、Script ファイルに加えて、SignalR が動的に生成する ~/signalR/hubs というフォルダも読み込む必要があったようですが、SignalR Core では不要になったようです。
なので、以下の一行で OK です。

<script src="~/js/signalr-client-1.0.0-alpha2-final.min.js"></script>

ASP.NET Core の MVC テンプレートプロジェクトでは、_Layout.cshtml に以下のセクションが定義されています。

@RenderSection("Scripts", required: false)

従って、SignalR を使用したい View で、Script セクションを作成し、そこで SignalR の Script を読み込ませたいと思います。

セクションについては以下を参照してください。

SignalR.cshtml に以下を記述します。

@section scripts {

    <environment include="Development">
        <script src="~/js/signalr-client-1.0.0-alpha2-final.min.js"></script>
    </environment>
}

SignalR の使用

まずは簡単なサンプルとして、上記のコードに以下のようなコードを追加しました。

@section scripts {

    <environment include="Development">
        <script src="~/js/signalr-client-1.0.0-alpha2-final.min.js"></script>
    </environment>

    <script>
        $(function () {
            let connection = new signalR.HubConnection('/SignalRTest');

            connection.start()
                .then(() => {
                    console.log('connected');
                    connection.invoke('send', 'Hello');
                });

            connection.on('AddMessage', data => {
                console.log('recieved: ' + data);
            });           
        });
    </script>
}

signalR.HubConnectionHub クラスを継承したクラスを指定します。

connection.invoke('send', 'Hello'); で、Hub クラス内の Send メソッドをコールしています。

connection.on('AddMessage',...); で、AddMessage というメッセージを受信したときの処理を定義しています。

Controller の変更

HomeController.cs に以下の View に対応したアクションメソッドを追加しました。

public IActionResult SignalR()
{
    return View();
}

とりあえず実行

以上まで実装し、デバッガを起動し、/Home/SignalR にアクセスします。
デバッガのコンソールログには以下のように出力されます。

メッセージの送信ボタンを実装

SignalRTest.cshtml を以下のように変更してみます。

@{
    ViewData["Title"] = "SignalR Test";
}

@section scripts {

    <environment include="Development">
        <script src="~/js/signalr-client-1.0.0-alpha2-final.min.js"></script>
    </environment>

    <script>
        $(function () {
            let connection = new signalR.HubConnection('/SignalRTest');

            connection.start()
                .then(() => {
                    console.log('connected');
                    connection.invoke('send', 'Hello');
                });

            connection.on('AddMessage', data => {
                console.log(data);
                $('#messages').append($('<li>').text(data));
            });

            $("#sendButton").click(function () {
                connection.invoke('send', $('#sendMessage').val());
            });
        });
    </script>
}

<h2>SignalR Test</h2>

<input type="text" id="sendMessage" placeholder="Enter report name" />
<input type="button" id="sendButton" value="Send" />

<ul id="messages"></ul>

実行結果は以下のようになります。

感想

SignalR Core はまだ正式リリース前であり、また ASP.NET Core 自体の情報が少ないこともあり、ここまで動くようにするだけでも結構苦労しました。
しかし、実際動いたコードだけをみると、とても簡単に双方向通信が実現できて便利だなと思いました。

参考 URL

SignalR

WebSocket