しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

ASP.NET SignalR で接続中のクライアントを数えてみる

SignalR のサンプルアプリケーションってボタンをクリックしたり、チャットでメッセージやり取りするものが多いですね。実際に試してみると結構面白いんですが、本当に複数人が繋がっているのか分からないので、いまいち実感がわかなかったりします。

自分以外も接続しているという実感が必要だと思ったので、前に作った では接続中のクライアント数を表示するようにしています。

f:id:shiba-yan:20130312204534p:plain

クライアント数の表示は、コネクション ID を ConcurrentDictionary に入れて数えるようにしました。ConcurrentDictionary を使った理由は単純に非同期でガンガン呼び出される可能性があるからです。

という訳で以下のようなコードを書いて対応しました。

[HubName("echo")]
public class EchoHub : Hub
{
    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);
    }
}

Hub クラスには OnConnected / OnDisconnected / OnReconnected 仮想メソッドが用意されているので、そいつをオーバーライドすればメソッドを自分で叩くことなく処理が可能になってます。HubPipeline で処理してもいいかなぁという気はしますが、ちょっと今回は置いておきます。

注意点としては、このコードではクライアントの情報を static なコレクションで持っているので、1 台のサーバで動かしている時しかまともに動作しません。SignalR は全体で接続情報を共有することはしないので、スケールアウトしている状態では RDB や KVS に接続情報を格納する必要があります。

SignalR でスケールアウトさせる方法については、何時かまとめてみたいですね。