Asp.Net MVC3 簡單入門第一季(三)詳解Controller之Filter

前言

前面兩篇寫的比較簡單,剛開始寫這個系列的時候我面向的對象是剛開始接觸Asp.Net MVC的朋友,所以寫的儘量簡單。所以寫的沒多少技術含量。把這些技術總結出來,然後一簡單的方式讓更多的人很好的接受這是我一直努力的方向。後面會有稍微複雜點的項目!讓我們一起期待吧!

此文我將跟大家介紹一下Asp.Net MVC3 Filter的一些用法。你會了解和學習到全局FileterAction Filter等常用用法。

第一節:Filter知識儲備

項目大一點總會有相關的AOP面向切面的組件,而MVC(特指:Asp.Net MVC,以下皆同)項目中呢Action在執行前或者執行後我們想做一些特殊的操作(比如身份驗證,日誌,異常,行爲截取等),而不想讓MVC開發人員去關心和寫這部分重複的代碼,那我們可以通過AOP截取實現,而在MVC項目中我們就可以直接使用它提供的Filter的特性幫我們解決,不用自己實現複雜的AOP了。

Asp.Net MVC提供了以下幾種默認的Filter

Filter Type

實現接口

執行時間

Default Implementation

Authorization filter

IAuthorizationFilter

在所有FilterAction執行之前執行

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 OnActionExecuted(ActionExecutedContext filterContext);//在Action執行之後執行

publicvirtualvoid OnActionExecuting(ActionExecutingContext filterContext); //在Action執行前執行

publicvirtualvoid OnResultExecuted(ResultExecutedContext filterContext);//在Result執行之後

publicvirtualvoid OnResultExecuting(ResultExecutingContext filterContext); //在Result執行之前
複製代碼

然後我們就可以直接在ActionResult執行之前之後分別做一些操作。

第二節:Action Filter實戰

光說不練假把式,那現在我們就直接做一個例子來實際演示一下。

首先我們添加一個普通的類,直接上代碼吧:

複製代碼
publicclass DemoActionAttributeFilter : ActionFilterAttribute
{
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上,打上上面的標記如下所示:

 

[DemoActionAttributeFilter(Message ="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。例如如下代碼所示:

複製代碼
[DemoActionAttributeFilter(Message ="controller")]
publicclass HomeController : Controller
{
[DemoActionAttributeFilter(Message
="action")]
public ActionResult Index()
{
this.ControllerContext.HttpContext.Response.Write(@"<br />Action execute");
return Content("<br/>Result Excut! ");
}
}
複製代碼
 
那就有個問題了我們再執行顯示的頁面會有什麼情況呢?Controller上的Filter會執行嗎?那標籤的作用會執行兩次嗎?下面是最後的執行結果如下圖所示:

結果說明:默認情況下Action上打了DemoActionAttributeFilter 標籤後,雖然在Controller上也打上了此標籤,但它只有Action上的標籤起作用了。

Index 執行時,Filter的方法只執行了一次,而某些情況下我們也想讓Controller上的FilterAttribute也執行一次DemoActionAttributeFilter 

那我們怎麼才能讓Controller上的[DemoActionAttributeFilter(Message = "controller")]也起作用呢?

答案是:我們只需在DemoActionAttributeFilter類的定義上打上標記[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]即可【下面類的最上面紅色字體部分】,也就是讓其成爲可以多次執行的Action代碼如下: 

複製代碼
[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
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打標記是很痛苦的。幸好AspNet MVC3帶來了一個美好的東西,全局Filter。而怎麼註冊全局Filter呢?答案就在Global.asax中。讓我們看以下代碼,我是如何將上面我們定義的DemoActionAttributeFilter 註冊到全局Filter中。上代碼: 

複製代碼
publicclass MvcApplication : System.Web.HttpApplication
{
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集合中,然後下面一句就是註冊全局FilterRegisterGlobalFilters(GlobalFilters.Filters);

這樣我們所有的ActionResult執行前後都會調用我們的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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章