だるろぐ

明日できることは、今日しない。

WebMatrix 2: SignalR を動かす ( 1.0.1 対応版) ※同時接続者数の追加

緑タイツの中の人が Facebook で、昨日の記事(WebMatrix 2: SignalR を動かす ( 1.0.1 対応版) - だるろぐ)に「SignalRのサンプル作るときは、「今何人接続」表示があるともっと便利ですよー」とコメントを付けてくれました。これは要するに、「そのやり方をブログに書け」ということですよね!(違

幸い、しばやんが偶然たまたま ASP.NET SignalR で接続中のクライアントを数えてみる - しばやん雑記 という記事を書いてくれましたので、それをコピペ参考にして、昨日のサンプルに追加してみました。

~/_AppStart.cshtml

@using System.Web.Routing

@{
    RouteTable.Routes.MapHubs();
}

~/App_Code/ChatHub.cshtml

using Microsoft.AspNet.SignalR;

// 追加
using Microsoft.AspNet.SignalR.Hubs;
using System.Collections.Concurrent;
using System.Threading.Tasks;

[HubName("chat")]
public class ChatHub : Hub 
{
    public void Send(string message)
    {        
        Clients.All.addMessage(message);
    }
    
    // 以下、追加
    private static readonly ConcurrentDictionary<string, bool>
        _connections = new ConcurrentDictionary<string, bool>();

    public override Task OnConnected()
    {
        _connections.TryAdd(Context.ConnectionId, true);

        return Clients.All.notify(_connections.Count);
    }

    public override Task OnDisconnected()
    {
        bool value;

        _connections.TryRemove(Context.ConnectionId, out value);

        return Clients.All.notify(_connections.Count);
    }

    public override Task OnReconnected()
    {
        _connections.TryAdd(Context.ConnectionId, true);

        return Clients.All.notify(_connections.Count);
    }
}

Dictionary で 接続ID を管理する処理が追加されています。ConcurrentDictionary は、

複数のスレッドから同時にアクセスできるキーと値のペアのスレッド セーフなコレクションを表します。

http://msdn.microsoft.com/ja-jp/library/vstudio/dd287191.aspx

.NET Framework 4 から使えるのかな?

しばやんの記事を読むまでは、単純に接続イベントで int Count をインクリメント・デクリメントしようと思っていたのですが、そんなに簡単なお話ではなかったようです。

あと、クラス名を ChatHub に変更しました。ファイル名とクラス名は合わせたいかな、と思ったので。これには追加の名前空間(Microsoft.AspNet.SignalR.Hubs)が必要です。 [HubName("chat")] という属性を追加すれば動作に影響はありません。

~/Default.cshtml

@{
    
}

<!DOCTYPE html>

<html lang="ja">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <meta charset="utf-8" />

        <title>マイ サイトのタイトル</title>

        <link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />

        <script src="~/Scripts/jquery-1.9.1.min.js"></script>
        <script src="~/Scripts/jquery.signalR-1.0.1.min.js"></script>
        <script src="~/signalr/hubs"></script>
        <script>
            $(function () {
                var chat = $.connection.chat;

                chat.client.addMessage = function (message) {
                    $('#messages').append('<li>' + message + '</li>');
                };

                // notify() を追加
                chat.client.notify = function (message) {
                    $('#count').html(message)
                };

                $.connection.hub.start().done(function () {
                    $("#broadcast").click(function () {
                        chat.server.send($('#msg').val());
                        $("#msg").val(""); // 追加
                    });
                });
            });
        </script>
    </head>
    <body>
        <div><!-- 追加 -->
            現在、<span id="count"></span>人が接続しています。
        </div><!-- ここまで -->
        <div>
            <input type="text" id="msg" />
            <input type="button" id="broadcast" value="broadcast" />

            <ul id="messages">
            </ul>
        </div>
    </body>
</html>

ハブが Clients.All.notify(接続数) するので、クライアント側でそれを span#count にセットします。

ついでに、ブロードキャストしたときにテキストボックスを空にする処理を加えておきました。

結果

f:id:daruyanagi:20130313064343p:plain

できました!