前言
前面兩篇寫的比較簡單,剛開始寫這個系列的時候我面向的對象是剛開始接觸Asp.Net MVC的朋友,所以寫的儘量簡單。所以寫的沒多少技術含量。把這些技術總結出來,然後一簡單的方式讓更多的人很好的接受這是我一直努力的方向。後面會有稍微複雜點的項目!讓我們一起期待吧!
此文我將跟大家介紹一下Asp.Net MVC3 Filter的一些用法。你會了解和學習到全局Fileter,Action Filter等常用用法。
第一節:Filter知識儲備
項目大一點總會有相關的AOP面向切面的組件,而MVC(特指:Asp.Net MVC,以下皆同)項目中呢Action在執行前或者執行後我們想做一些特殊的操作(比如身份驗證,日誌,異常,行爲截取等),而不想讓MVC開發人員去關心和寫這部分重複的代碼,那我們可以通過AOP截取實現,而在MVC項目中我們就可以直接使用它提供的Filter的特性幫我們解決,不用自己實現複雜的AOP了。
Asp.Net MVC提供了以下幾種默認的Filter:
Filter Type |
實現接口 |
執行時間 |
Default Implementation |
Authorization filter |
IAuthorizationFilter |
在所有Filter和Action執行之前執行 |
AuthorizeAttribute |
Action filter |
IActionFilter |
分別在Action執行之前和之後執行。 |
ActionFilterAttribute |
Result filter |
IResultFilter |
分別在Action Result執行之後和之前 |
ResultFilterAttribute |
Exception filter |
IExceptionFilter |
只有在filter, 或者 action method, 或者 action result 拋出一個異常時候執行
|
HandleErrorAttribute |
大家注意一點,Asp.Net MVC提供的ActionFilterAttribute默認實現了IActionFilter和IResultFilter。而ActionFilterAttribute是一個Abstract的類型,所以不能直接使用,因爲它不能實例化,所以我們想使用它必須繼承一下它然後才能使用,下圖所示的是ActionFilterAttribute的實現:
所以我們在實現了ActionFilterAttribute,然後就可以直接重寫一下父類的方法如下:
publicvirtualvoid OnActionExecuting(ActionExecutingContext filterContext); //在Action執行前執行
publicvirtualvoid OnResultExecuted(ResultExecutedContext filterContext);//在Result執行之後
publicvirtualvoid OnResultExecuting(ResultExecutingContext filterContext); //在Result執行之前
然後我們就可以直接在Action、Result執行之前之後分別做一些操作。
第二節:Action Filter實戰
光說不練假把式,那現在我們就直接做一個例子來實際演示一下。
首先我們添加一個普通的類,直接上代碼吧:
{
publicstring Message { get; set; }
publicoverridevoid OnActionExecuted(ActionExecutedContext filterContext)
{ //在Action執行之後執行 輸出到輸出流中文字:After Action execute xxx
filterContext.HttpContext.Response.Write(@"<br />After Action execute"+"\t "+ Message);
base.OnActionExecuted(filterContext);
}
publicoverridevoid OnActionExecuting(ActionExecutingContext filterContext)
{ //在Action執行前執行
filterContext.HttpContext.Response.Write(@"<br />Before Action execute"+"\t "+ Message);
base.OnActionExecuting(filterContext);
}
publicoverridevoid OnResultExecuted(ResultExecutedContext filterContext)
{ //在Result執行之後
filterContext.HttpContext.Response.Write(@"<br />After ViewResult execute"+"\t "+ Message);
base.OnResultExecuted(filterContext);
}
publicoverridevoid OnResultExecuting(ResultExecutingContext filterContext)
{ //在Result執行之前
filterContext.HttpContext.Response.Write(@"<br />Before ViewResult execute"+"\t "+ Message);
base.OnResultExecuting(filterContext);
}
}
寫完這個代碼後,我們回到Action上,打上上面的標記如下所示:
public ActionResult Index()
{ //Action 執行時往輸出流寫點代碼
this.ControllerContext.HttpContext.Response.Write(@"<br />Action execute");
return Content("Result Excut! ");
}
然後執行F5,頁面上則會顯示爲:
最終我們看到了在Action執行之前和之後都執行了我們的重寫的DemoActionAttributeFilter方法,Result執行前後也執行了我們的Filter的方法。
總的執行順序是:
Action執行前:OnActionExecuting方法先執行→Action執行→OnActionExecuted方法執行→OnResultExecuting方法執行→返回的ActionRsult中的executeResult方法執行→OnResultExecuted執行。最終顯示的效果就是如上圖所示。
感覺很爽吧!呵呵!
如果我們將此標籤打到Controller上的話,DemoActionAttributeFilter將作用到Controller下的所有的Action。例如如下代碼所示:
publicclass HomeController : Controller
{
[DemoActionAttributeFilter(Message ="action")]
public ActionResult Index()
{
this.ControllerContext.HttpContext.Response.Write(@"<br />Action execute");
return Content("<br/>Result Excut! ");
}
}
Index 執行時,Filter的方法只執行了一次,而某些情況下我們也想讓Controller上的FilterAttribute也執行一次DemoActionAttributeFilter
那我們怎麼才能讓Controller上的[DemoActionAttributeFilter(Message = "controller")]也起作用呢?
答案是:我們只需在DemoActionAttributeFilter類的定義上打上標記[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]即可【下面類的最上面紅色字體部分】,也就是讓其成爲可以多次執行的Action。代碼如下:
publicclass DemoActionAttributeFilter : ActionFilterAttribute
{
publicstring Message { get; set; }
publicoverridevoid OnActionExecuted(ActionExecutedContext filterContext)
{
filterContext.HttpContext.Response.Write(@"<br />After Action execute"+"\t "+ Message);
base.OnActionExecuted(filterContext);
}
publicoverridevoid OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.HttpContext.Response.Write(@"<br />Before Action execute"+"\t "+ Message);
base.OnActionExecuting(filterContext);
}
publicoverridevoid OnResultExecuted(ResultExecutedContext filterContext)
{
filterContext.HttpContext.Response.Write(@"<br />After ViewResult execute"+"\t "+ Message);
base.OnResultExecuted(filterContext);
}
publicoverridevoid OnResultExecuting(ResultExecutingContext filterContext)
{
filterContext.HttpContext.Response.Write(@"<br />Before ViewResult execute"+"\t "+ Message);
base.OnResultExecuting(filterContext);
}
}
然後我們執行的效果如圖所示:
我們看到的結果是Controller上的ActionFilter先於Action上打的標記執行。同樣Result執行executeResult方法之前也是先執行Controller上的Filter標記中的OnResultexecuteing方法。
最後的執行順序是:Controller上的OnActionExecuting→Action上的OnActionExecuting→Action執行→Action上的OnActionExecuted→Controller上的OnActionExecuted
到此Action就執行完畢了,我們看到是一個入棧出棧的順序。後面是Action返回ActionResult後執行了ExecuteResult方法,但在執行之前要執行Filter。具體順序爲:
接上面→Controller的OnResultExecuting方法→Action上的OnResultExecuting→Action返回ActionResult後執行了ExecuteResult方法→Action上的OnResultExecuted執行→Controller上的OnResultExecuted執行→結束
第三節:Gloable Filter實戰
又接着一個問題也來了,我們想有些公共的方法需要每個Action都執行以下,而在所有的Controller打標記是很痛苦的。幸好Asp。Net MVC3帶來了一個美好的東西,全局Filter。而怎麼註冊全局Filter呢?答案就在Global.asax中。讓我們看以下代碼,我是如何將上面我們定義的DemoActionAttributeFilter 註冊到全局Filter中。上代碼:
{
publicstaticvoid RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
publicstaticvoid RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller ="Home", action ="Index", id = UrlParameter.Optional } // Parameter defaults
);
}
protectedvoid Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalFilters.Filters.Add(new DemoActionAttributeFilter() { Message = "Gloable" });
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
}
跟普通的MVC2.0中的Global.asax的區別就是紅色部分的代碼,我們看到代碼中我將自己定義的DemoActionAttributeFilter的實例加入到GlobalFilters.Filters集合中,然後下面一句就是註冊全局Filter:RegisterGlobalFilters(GlobalFilters.Filters);
這樣我們所有的Action和Result執行前後都會調用我們的DemoActionAttributeFilter的重寫的方法。
再次運行我們的demo看到的結果是:
我們看到的結果是全局的Action首先執行,然後纔是Controller下的Filter執行,最後纔是Action上的標籤執行。當然這是在DemoActionAttributeFilter類的定義上打上標記[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]的前提下。不然 如果Action打上了標籤跟Controller的相同則它只會執行Action上的Filter。
總結
經過這一篇文章的介紹我們大體瞭解了Filter的使用方法,還瞭解到全局Filter的用法,尤其是當相同的Filter重複作用到同一個Action上時,如果沒有設置可多次執行的標籤那只有Action上的Filter執行,而Controller和全局Filter都被屏蔽掉,但是設置可多次執行,那首先執行全局Filter其次是Controller再次之就是Action上的Filter了。
本文提供Word版本下載地址:http://files.cnblogs.com/fly_dragon/Filter%E5%AD%A6%E4%B9%A0.rar
來自於:http://www.cnblogs.com/fly_dragon/archive/2011/06/15/2081063.html