狠狠撸

狠狠撸Share a Scribd company logo
ケーススタディから学ぶ
実践的 ASP.NET MVC Filters
2013/06/03 @yukijs
自己紹介
? @yukijs
? jsに深い意味はありません
? 都内某ITベンチャー勤務
? ASP.NET MVCでアプリを開発したことがあります
? MVC3 アプリと、MVC4 WebAPI
Filters!
System.Web.Mvc 名前空間の裾野に広がる
肥沃な大地
Filters
贵颈濒迟别谤の作り方や使い所などをご绍介します
Filterをつくる
Filterを作るには、次のインタフェースを実装しましょう
Four interfaces
1. IAuthorizationFilter
2. IActionFilter
3. IResultFilter
4. IExceptionFilter
IAuthorizationFilter
4つの中では一番先に実行される
OnAuthorizationを定義しています。
その名の通り認証処理が主な目的。
IActionFilter
アクションメソッドの実行前後イベント、
OnActionExecuting,
OnActionExecutedを定義しています。
一番使う感じ。
IResultFilter
ActionResult.ExecuteResultの実行前後イベント、
OnResultExecuting,
OnResultExecutedを定義しています。
WebAPIでは使えない(作れるけど使われない)です。
=> WebAPIのActionは、ActionResultではなく
Modelをそのまま返すからですね。
git clone https://git01.codeplex.com/aspnetwebstack.git
ControllerがFilterを取得するとき
//IActionFilter,IAuthorizationFilter,
//IExceptionFilter,IResultFilterの4つをとって、Invokerに渡す
public FilterInfo(IEnumerable<Filter> filters) {
var filterInstances = filters.Select(f => f.Instance).ToList();
_actionFilters.AddRange(filterInstances.OfType<IActionFilter>());
_authorizationFilters
.AddRange(filterInstances.OfType<IAuthorizationFilter>());
_exceptionFilters
.AddRange(filterInstances.OfType<IExceptionFilter>());
_resultFilters.AddRange(filterInstances.OfType<IResultFilter>());
}
ApiControllerがFilterを取得するとき
//IActionFilter,IAuthorizationFilter,IExceptionFilterの3つをとる
IEnumerable<IActionFilter> actionFilters =
filterGrouping.ActionFilters;
IEnumerable<IAuthorizationFilter> authorizationFilters =
filterGrouping.AuthorizationFilters;
IEnumerable<IExceptionFilter> exceptionFilters =
filterGrouping.ExceptionFilters;
//Invokeする
Task<HttpResponseMessage> result = InvokeActionWith...
IExceptionFilter
例外発生時のやつです。
今回は取り上げません。
Controllerを拡張して例外処理を実装したので、
あまり知らないからです。。
実行の順序
IAuthorizationFilter.OnAuthorization()
IActionFilter.OnActionExecuting()
コントローラのアクションメソッド
IActionFilter.OnActionExecuted()
IResultFilter.OnResultExecuting()
ActionResult.ExecuteResult()
IResultFilter.OnResultExecuted()
※例外発生時にIExceptionFilter.OnException()
※それぞれController自体のOn...ingの後、On..edの前に実行
実践
IAuthorizationFilter
?使ったところ:
WebAPIの認証処理。アクセストークンを発行して、
全アクセスにトークン認証をかけるために使いました
?注意点など:
ほぼ全てのリクエストで認証が必要なので、
GlobalFilterにしました
でも対象外にしたいとき(ログイン処理とか)は?
AllowAnonymousAttributeだ!
//ApiAuthorizationAttributeの中で、AllowAnonymouseの有無をチェック
//AllowAnonymouseがついていたら、認証をスキップするようにしました
//AuthrizeAttributeでやっているのと同じ方法ですね
private static bool SkipAuthorization(HttpActionContext context) {
return
actionContext.ActionDescriptor.
GetCustomAttributes<AllowAnonymousAttribute>().Any() ||
actionContext.ControllerContext.ControllerDescriptor.
GetCustomAttributes<AllowAnonymousAttribute>().Any();
}
IActionFilter
?使ったところ:
WebAPIでのモデルバインド時に発生した
Validationエラーでエラーメッセージを返す場合や、
リクエスト/レスポンスデータに
毎回行う処理がある場合に利用(暗号化/復号とか)
?注意点など:
いっぱい使うと実行順序の制御が???後で話します
IResultFilter
?使ったところ:
Responseヘッダに
Cacheを無効化する記述を追加するのに利用
?注意点:
WebAPIでは使えない(実行されない)ので注意
Cache無効化
public override void OnResultExecuting(ResultExecutingContext context)
{
context.HttpContext.Response.Cache
.SetExpires(DateTime.UtcNow.AddDays(-1));
context.HttpContext.Response.Cache.SetValidUntilExpires(false);
context.HttpContext.Response.Cache
.SetRevalidation(HttpCacheRevalidation.AllCaches);
context.HttpContext.Response.Cache
.SetCacheability(HttpCacheability.NoCache);
context.HttpContext.Response.Cache.SetNoStore();
base.OnResultExecuting(filterContext);
}
Filterの実行順序
IActionFilterとIResultFilterを個別に説明しましたが、
この両方を実装したActionFilterAttributeという
abstract classを結構使いました
ActionFilterAttributeでは、Baseである
FilterAttributeが持つプロパティを利用して、
実行順序を制御出来ます
ScopeとOrder
?Scope
=>Filterが設定された場所に応じて決定されます
=>小さい方が優先
=>1.Global 2. Controller 3.Action
=>先ほど説明した通り、
Controller自体のイベントが最優先です
ScopeとOrder
?Order
=>使う側が直接制御できるのはOrderだけ
=>同じScopeの中で、Orderが小さい方から実行
例
[aaaFilter(Order = 1)]//GlobalFilterがなければこれが1番目
public class HomeController {...
[aaaFilter(Order = 1)]//2番目
[bbbFilter(Order = 2)]//3番目
public ActionResult Index() {...
ご静聴ありがとうございました

More Related Content

Filters