だるろぐ

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

SignalR + WebMatrix でサーバーフォルダの監視を行ってみる

SignalR の面白い使い方ってないかなーと思ってたのだけど、たとえば誰かがファイルをアップロードした時、同時接続している人たちにそれを知らせられたら面白くないかな? と思いついた。さっそくやってみる。

自分の作ったサンプルコード(SignalR Deep Dive ! に参加してきた+WebMatrix で SignalR 動かしてみた - だるろぐ)をコピペして、必要な処理を足して、要らない部分を消して……以下のようなコードを書いてみた。

# ~/App_Code/SampleHub.cs

using SignalR.Hubs;
using System.IO;

[HubName("sample")]
public class SampleHub : Hub
{
    public SampleHub()
    {
        var watcher = new FileSystemWatcher();
        
        watcher.Path =  System.Web.HttpContext.Current
            .Server.MapPath(@"~/_Documents");
        watcher.Filter = "*.txt";
        watcher.NotifyFilter = NotifyFilters.FileName
                             | NotifyFilters.DirectoryName
                             | NotifyFilters.LastWrite;
        watcher.IncludeSubdirectories = false;
        watcher.Changed +=
            (o, s) => { Clients.Echo("なんかかわったで"); };
        watcher.Created +=
            (o, s) => { Clients.Echo("あたらしいのできたで"); };
        watcher.Deleted +=
            (o, s) => { Clients.Echo("きえてもうた……"); };
        watcher.Renamed +=
            (o, s) => { Clients.Echo("なまえかわったわ"); };
        watcher.EnableRaisingEvents = true;
    }
}

めんどくさいので フォルダ、ファイルの変更を監視する - .NET Tips (VB.NET,C#...) をほとんど丸コピしている。原理的には、これで _Documents フォルダ内のテキストファイルが更新されると、クライアント側の Echo() が呼ばれるはず。

ちなみにクライアント側はこんな感じ。

# ~/Default.cshtml

<!DOCTYPE html>

<html lang="ja">
    <head>
        <meta charset="utf-8" />
        <title>マイ サイトのタイトル</title>
        <script type="text/javascript"
                src="Scripts/jquery-1.6.4.js"></script>
        <script type="text/javascript"
                src="Scripts/jquery.signalR-0.5.3.js"></script>
        <script>
            var connection = $.hubConnection();
            var sample = connection.createProxy("sample");
            connection.start();
            sample.on("Echo", function (value) {
                $("#value").html(value);
            });
        </script>
    </head>
    <body>
        <p id="value"></p>
    </body>
</html>

反応がない、ただの屍のようだ。

でも、これだと動かない。なぜだ!

元のサンプルコードをいじりながらいろいろ試してみたところ、クライアントから一度なんらかのアクションがあれば、期待通りの動作をするみたい。ということで、コードを少し足した。

# ~/App_Code/SampleHub.cs

using SignalR.Hubs;
using System.IO;

[HubName("sample")]
public class SampleHub : Hub
{
    public SampleHub()
    {
        (省略)
    }

    public void Initialize()
    {
        // 追加:コネクションを叩き起こすための何もしないメソッド
    }
}

で、クライアント側から SampleHub.Initialize() を叩く。

# ~/Default.cshtml

<!DOCTYPE html>

<html lang="ja">
    <head>
        <meta charset="utf-8" />
        <title>マイ サイトのタイトル</title>
        <script type="text/javascript"
                src="Scripts/jquery-1.6.4.js"></script>
        <script type="text/javascript"
                src="Scripts/jquery.signalR-0.5.3.js"></script>
        <script>
            var connection = $.hubConnection();
            var sample = connection.createProxy("sample");
            connection.start();
            sample.on("Echo", function (value) {
                $("#value").html(value);
            });
            sample.invoke('initialize'); // <-- 追加!
        </script>
    </head>
    <body>
        <p id="value"></p>
    </body>
</html>

無理やり叩いたらゲロ吐きやがった

そうしたらエラーで止まった。

f:id:daruyanagi:20120927212447p:plain

connection.start() が終わってないのに SampleHub.Initialize() を叩くんじゃねえ、バカ。そういいたいらしい。connection.start().done() を使えというので、素直に従おう。

# ~/Default.cshtml

<!DOCTYPE html>

<html lang="ja">
    <head>
        <meta charset="utf-8" />
        <title>マイ サイトのタイトル</title>
        <script type="text/javascript"
                src="Scripts/jquery-1.6.4.js"></script>
        <script type="text/javascript"
                src="Scripts/jquery.signalR-0.5.3.js"></script>
        <script>
            var connection = $.hubConnection();
            var sample = connection.createProxy("sample");
            connection.start().done(function () { // <-- done()!
                sample.invoke('initialize');
            });
            sample.on("Echo", function (value) {
                $("#value").html(value);
            });
        </script>
    </head>
    <body>
        <p id="value"></p>
    </body>
</html>

f:id:daruyanagi:20120927212701p:plain

ぉー! ちゃんと動いたぞ。けれど、あんまりスマートじゃないな? まぁ、いいか。