銀の光と碧い空

クラウドなインフラとC#なアプリ開発の狭間にいるエンジニアの日々

ASP.NET MVC 5 アプリにSignalRの機能を足す方法

SignalR についてはいろいろブログや記事も出ていますが、ちょっとはまったので、MVC アプリにSignalRの機能を足して、サーバーからクライアントにメッセージを送るところまでをまとめてみました。

まずは、Nugetでライブラリを追加します。ASP.NET 用にJavaScriptなども入った全部入りのパッケージがあるので、それをインストールします。

Install-Package Microsoft.AspNet.SignalR
Update-Package

インストールすると開くREADMEにも書いていますが、Startup クラスで MapSignalR メソッドを実行します。(partial クラスなのと、ConfigureAuth メソッドを呼んでいるのは、MVCプロジェクトのテンプレートが作成しているためなので、SignalR的には不要)

using Microsoft.Owin;
using Owin;

[assembly: OwinStartupAttribute(typeof(WebApplication13.Startup))]
namespace WebApplication13
{
    public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            ConfigureAuth(app);

            app.MapSignalR();
        }
    }
}

そして、Hubクラスを作ります。が、今回は空です。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.AspNet.SignalR;

namespace WebApplication13.Hubs
{
    public class MyHub : Hub
    {
    }
}

で、クライアント側のページを作ります。今回は /Debug/ で開くページでSignalRを使うようにするので、 Views/Debug/Index.cshtml を作ります。

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
    <script src="/Scripts/jquery-2.1.1.min.js"></script>
    <script src="/Scripts/jquery.signalR-2.1.2.js"></script>
</head>
<body>
    <script src="/signalr/hubs"></script>
    <script>
        $(function () {
            var myHub= $.connection.myHub,
                $list = $("#messagelist");
            myHub.client.update = function (model) {
                $list.prepend($('<p />').text(model.Timestamp + ' ' + model.Message));
            };

        });
        $.connection.hub.start().done(function () {
            $("#connection-satus").text("SignalR接続済み");
        });
    </script>
    <p id="connection-satus">SignalR接続済み未接続</p>
    <div id="messagelist">
    </div>
</body>
</html>

jQuery のバージョンとかは適宜変えてください*1 を参照したうえで、 connection.hub.start() でSignalRで接続します。 また、 $.connection.myHub でサーバー側で作成した MyHub クラスを参照し、myHub.client.update でクライアント側の update メソッドを定義しています。

あとは、サーバー側からクライアントで定義した update メソッドを呼んでやることにします。MyHub クラスの中からであれば簡単ですが、普通の MVC のロジックから呼びたいことがあると思います。そういうときは次のように書きます。

var hubContext = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
hubContext.Clients.All.update(new
{
    Timestamp = DateTime.Now,
    Message = "Hello"
});

また、クラス名が動的に決まるとかいう事情があってクラスを直接指定できない場合は、名前でも参照可能です*2

var hubContext = GlobalHost.ConnectionManager.GetHubContext("MyHub");
hubContext.Clients.All.update(new
{
    Timestamp = DateTime.Now,
    Message = "Hello"
});

これで /Debug を開いてサーバーからメッセージを送信するとこんな風に動いていることが確認できます。

f:id:tanaka733:20141006113031p:plain

というわけで、SignalR の機能が追加できました。なんで今回こんな紹介をしたかというと、次回の記事で SLABのEventSource を組み合わせてSignalRでサーバーのログをクライアントにそのまま送信しよう*3というものを書きたいためでした。

*1:実際はScriptBundleとか使うんですかね?

*2:いずれにせよ戻り値の型は IHubContext

*3:開発時の調査のために