2011年1月14日金曜日

WebMatrixで初めてのヘルパー

ASP.NET MVC3 RTM出ましたね。やったね。やりたい事いろいろあるんだ!

WebMatrixもでたね。WebPagesじゃん?Razorじゃん?ヘルパーじゃん?

WebMatrixやらなんやらの細かい説明とかはよくわからないのですっ飛ばして、早速ヘルパーを作ってみようかな。

ヘルパーといえばHelperResultを受け取る@helperで定義される者たちなんだろうけど、@functionsに定義するものもUtilityメソッドという意味でヘルパーっていう扱いにしても、それはそれで許されるんじゃないかと勝手に定義。だめ~?いいっしょ!

Webアプリケーションの基本といえばキャッシュでしょ!でもとりあえず今回はOutputCacheじゃなくてデータキャッシュね。System.Runtime.Caching!と言いたいところだけど、もっとお手軽なHttpContextBase.Cache。いろいろまとめてくれてるし、System.Web.Caching.Cache互換なインターフェイスだし。

まずは、WebMatrixでスターターサイトを作成。

ルートのdefault.cshtmlをひらいて以下のように書いてみる。

@{  
    Layout = "~/_SiteLayout.cshtml";
    Page.Title = "マイ Web サイトへようこそ";

    dynamic cache = Cache["test_page"];
    if(cache==null){
        cache = DateTime.Now;
        Cache.Insert(
            "test_page",
            cache,
            null,
            DateTime.Now.AddSeconds(3),
            System.Web.Caching.Cache.NoSlidingExpiration
        );
    }
}
<p>
    ASP.NET Web Pages を使用すると、Web 用の優れた .NET ベースのアプリケーションを簡単に作成できます。
</p>
<p>
    @cache<br/>
    @cache.GetType().Name
</p>

んで、動かしてみる。

helper1

出ますわね。3秒キャッシュ。ホームをなんどもクリックしてみたら分かるわね。

毎回キャッシュするたびにこんなコード書くのも面倒だよね!これをヘルパーにしてみよう!

ルートにApp_Codeって名前でフォルダ作成。んで、その中にUtility.cshtmlファイルを作成。

helper2

中身は↓。

@functions {
    public static new dynamic Cache(HttpContextBase context, string key, int expireSeconds, Func<dynamic> thunk){
        dynamic value = context.Cache[key];
        if(value == null) {
            value = thunk();
            context.Cache.Insert(
                key,
                value,
                null,
                DateTime.Now.AddSeconds(expireSeconds),
                System.Web.Caching.Cache.NoSlidingExpiration
            );
        }
        
        return value;
    }
}

staticメソッドなのでHelperPage.Cacheなんて見れないからContextを渡しましょう。もちろんHelper内で

var context = new HttpContextWrapper(HttpContext.Current);

って書くのもありだとは思うけど、まぁ、ね。

んで、default.cshtmlを以下のように変更。

@{  
    Layout = "~/_SiteLayout.cshtml";
    Page.Title = "マイ Web サイトへようこそ";

    dynamic cache = Cache["test_page"];
    if(cache==null){
        cache = DateTime.Now;
        Cache.Insert(
            "test_page",
            cache,
            null,
            DateTime.Now.AddSeconds(3),
            System.Web.Caching.Cache.NoSlidingExpiration
        );
    }
}
<p>
    ASP.NET Web Pages を使用すると、Web 用の優れた .NET ベースのアプリケーションを簡単に作成できます。
</p>
<p>
    @Utility.Cache(Context, "test_helper",3,()=>DateTime.Now)<br/>
    @Utility.Cache(Context, "test_helper",3,()=>DateTime.Now).GetType().Name<br/>

    @cache<br/>
    @cache.GetType().Name
</p>

太字の部分追加。

キャッシュしたい値を返すFunc<T>を渡しましょう。

@Utility.Cache(Context,”text_helper”,3,()=>{
  return DateTime.Now
})

でもいいよ。真面目な話をすると、ちゃんとレキシカルスコープを維持してるので、ローカル変数を参照しててもOKです。...。どんまい。

helper3

ちゃんと3秒キャッシュしてるよね!例えば、外部のサイトのデータを毎回取得するなんてばからしいからキャッシュしたり、データベースから毎回取得するなんてばからしいからキャッシュしたり、いろいろキャッシュすることでパフォーマンスは劇的にあがるっしょ!

dynamicだから

@Utility.Cache(Context, "test_helper",3,()=>DateTime.Now).Second

って書いてもちゃんと動くもんね!

まずは1 helper。