ASP.NET MVC 「Fiter Order属性」

フィルターのOrderとは、同種のフィルター(AuthorizationFilter,ExceptionFilter,ActionFilter,ResultFilter)のうちの実行順を指定する方法のことである。
言いかえれば、同種のフィルターの中での優先度を決める事ができるというものである。
本編では、フィルターを適応する際に使用できるOrder属性について述べる。

フィルターの種類の中でExceptionFilterに限っては他の三種のフィルターと違った振る舞いをするため後述する。

1.Orderingでフィルターの優先度を決める
フィルターに対して優先度を付与するOrder属性であるが、その優先度の表現には-1以上の整数値を使用している。(-2以下の値を記述するとエラーになる。)
この属性の値が小さいものから順に優先度が高いフィルターと見なされる。
Ordering属性を適応時に記述しなった場合は(通常、Ordering属性は省略可能)、優先度の最高値である-1として扱われる。よって、Ordering属性を省略すると優先度の高いフィルターとして内部的に扱われるようになる。

また、GlobalFilterにもこの属性は使用可能であり、GlobalFilterとController(もしくはAction Method)に適応したフィルターの優先度が同じであった場合はGlobalFilterが優先される(これはOrdering属性を全く記述しなかった場合を考えれば想像できる。)。
逆に、GlobalFilterよりもController(もしくはAction method)の方が優先度が高かった場合は、Controller(もしくはAction Method)が実行される。すなわち、GolbalFilterであることによる実行優先権よりもOrder属性による実行優先権の方が強い。
上述したが、Order属性を記述しないと最も優先度の高いものとして扱われるので、GlobalFilterにOrder属性を付与することは個人的には推奨しない。


2. Orderの使い方
フィルターをContorollerやAction methodに適応する際に、フィルターの実行順を考慮しないのであれば、Order属性の記述は不要である。
今回はOrdering用に作成したメッセージを出力するFilter、SimpleMessageAttributeを使用して検証する。
SimpleMessageAttributeクラス

namespace OrderingCheck.Filters
{
    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class,AllowMultiple=true)]
    public class SimpleMessageAttribute : FilterAttribute,IActionFilter
    {
        public string Message {get;set; }

        public void OnActionExecuting(ActionExecutingContext filterContext)
        {
            filterContext.HttpContext.Response.Write(
                string.Format("[Before Action:{0}]",Message));
        }

        public void OnActionExecuted(ActionExecutedContext filterContext)
        {
            filterContext.HttpContext.Response.Write(
                string.Format("[After Action:{0}]", Message));
        }
    }
}

フィルターの適用時に[フィルター名 Order=X]と記述することで実装する。

Orderingを用いたFilterの利用例

namespace OrderingCheck.Controllers
{
    public class HomeController : Controller
    {
        [SimpleMessage(Message="A")]
        [SimpleMessage(Message="B",Order=1)]
        public ActionResult Index()
        {
            return View();
        }
    }
}

また、Global.asax内でGlobalFilterとして登録する際は下記のように記述する。

Global.asax内のRegisterGlobalFiltersメソッドの記述

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
   filters.Add(new HandleErrorAttribute());
   filters.Add(new SimpleMessageAttribute(){Message="Global",Order=1});
}

下記の実行画面からもわかるように、Orderを宣言しなかったもの(デフォルトの-1で実行されたもの)が一番優先されて実行されている。また、Order=1で競合しているFilterに関してはGlobalFilterが優先されるルールが適応されていることが分かる。

実行画面