しばやん雑記

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

ASP.NET MVC 3 の新機能、グローバルフィルタは地味だけどイケてる

ASP.NET MVC 3 ではグローバルフィルタという機能が追加されました。Razor や DI に比べてかなり地味ですが、今までコントローラクラスに毎回付ける必要があったアクションフィルタを Global.asax で一括指定できるようになりました。

使い方は非常に簡単で、GlobalFilters.Filters コレクションに全てのコントローラに適用したいアクションフィルタを追加するだけです。MVC 3 のプロジェクトを作成すると、Global.asax.cs に以下のようなコードがデフォルトで追加されているので、RegisterGlobalFilters メソッドを修正するだけで使い始めることが出来ます。

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(new HandleErrorAttribute());
}

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);
}

デフォルトで HandleError アクションフィルタを全てのコントローラへ適用するようになっています。MVC 2 まではコントローラを新規追加した時に HandleError が指定されていなかったので、アクション内で例外が発生しても用意したエラーページが表示されない事がたびたび起こりました。*1

しかしもう大丈夫、MVC 3 ではもう ASP.NET 標準のエラーページが表示されるなんてかっこ悪いことは起きません!

グローバルフィルタは HandleError 以外にもアクションフィルタであれば何でも追加できるので、全てのアクションでキャッシュを有効にしたい時には以下のように OutputCache アクションフィルタを追加するだけです。

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(new HandleErrorAttribute());
 
    // 全てのページを 60 秒間キャッシュする
    filters.Add(new OutputCacheAttribute { Duration = 60 });
}

はい、これで全てのページで 60 秒間のキャッシュが有効になります。

ここで気が付いた方もいるかと思いますが、OutputCache には VaryByParam プロパティなどでキャッシュの出力を変更する機能があります。しかし、グローバルフィルタで指定しちゃうとパラメータごとにキャッシュの出力を変更出来ないように思えますね。

仕方ないので VaryByParam の指定が必要な場合は個別にアクションに追加する?そんな手間のかかることは必要ありません!そう、MVC 3 RC 2 ならね。

Output Caching Improvements

ASP.NET MVC 3’s output caching system no longer requires you to specify a VaryByParam property when declaring an [OutputCache] attribute on a Controller action method. MVC3 now automatically varies the output cached entries when you have explicit parameters on your action method – allowing you to cleanly enable output caching on actions using code like below:

Announcing ASP.NET MVC 3 (Release Candidate 2) - ScottGu's Blog

MVC 3 RC 2 では名前の変更が多くて見逃されがちですが、OutputCache の挙動が変更されてアクションの引数は自動的に VaryByParam に指定されるような挙動になりました。

この変更により以下のようなパラメータ id を受け取って何らかのページを作成するアクションでも、特別な指定なしで適切にキャッシュすることが出来るようになりました。

追記

ガスリーたんは「have explicit parameters on your action method」と言ってるのでアクションメソッドの引数が VaryByParam に指定されるようになっていると思っていたのですが、実際の挙動は VaryByParam = * と同じ挙動になっていました。*2

この挙動は誰も嬉しくないと思う*3のですが、今からフィードバックして間に合いますかね・・・。

// id は大抵プライマリキーかな
public ActionResult Details(int id)
{
    // 何かの処理をする!
    return View();
}

MVC 3 は今月の中頃には正式版がリリースされる予定ですし、今からでも全然遅くないので MVC 3 RC 2 をインストールして試していっちゃってください!

*1:単に私が付けるのを忘れていただけですが…。

*2:@mayuki さん経由

*3:VaryByParam の初期値に * を設定しているだけ…