標籤:blog http io os ar 使用 for sp div
前言
前面兩篇寫的比較簡單,剛開始寫這個系列的時候我面向的對象是剛開始接觸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 OnActionExecuted(ActionExecutedContext filterContext);//在Action執行之後執行
publicvirtualvoid OnActionExecuting(ActionExecutingContext filterContext); //在Action執行前執行
publicvirtualvoid OnResultExecuted(ResultExecutedContext filterContext);//在Result執行之後
publicvirtualvoid OnResultExecuting(ResultExecutingContext filterContext); //在Result執行之前
然後我們就可以直接在Action、Result執行之前之後分別做一些操作。
第二節: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打標記是很痛苦的。幸好Asp。Net 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集合中,然後下面一句就是註冊全域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
記於:2011年6月14日23:23:47
初識Asp.Net MVC2.0初識Asp.Net MVC2.0【續】
Asp.Net MVC2.0 Url 路由入門---執行個體篇
Asp.Net MVC2.0 Url 路由入門
Asp.Net MVC3 簡單入門第一季(一)環境準備
Asp.Net MVC3 簡單入門第一季(二)詳解Asp.Net MVC3項目
Asp.Net MVC3 簡單入門第一季(三)詳解Controller之Filter
Asp.Net MVC3 簡單入門第一季(四)詳解Request Processing Pipeline
Asp.Net MVC3 簡單入門第一季(三)詳解Controller之Filter