mvc原始碼解讀(13)-MVC四大過濾器之ResultFilter

風靈使發表於2018-07-10

上一篇講到ActionFilter,這一篇我們來講解ResultFilter,顧名思義,就是結果過濾器。和ActionFilter要實現抽象類ActionFilterAttribute裡面的四個方法一樣,我們自定義的ResultFilter的過濾特性類也要繼承ActionFilterAttribute才行,同時實現介面IResultFilter裡面的方法:

public interface IResultFilter {
 void OnResultExecuting(ResultExecutingContext filterContext);
 void OnResultExecuted(ResultExecutedContext filterContext);
}

OnResultExecuting是在動作結果執行之前執行,OnResultExecuted是在動作結果之後執行,什麼是動作結果?我們可以這樣來理解,Action就是一個動作,這個動作的結果是可能會返回一個ViewResult渲染到瀏覽器中,在整個Action的生命週期之內成為Action的執行,之前執行OnActionExecuting,之後執行OnResultExecuted方法,那OnActionExecuted方法和OnResultExecuting方法在什麼時候執行呢,答案是在Action之後,Result之前。我們來看一個的demo吧:

我們定義一個MyTestResultFiter,讓他繼承自ActionFilterAttribute類,具體實現如下:


public class MyTestResultFiter : ActionFilterAttribute
{

 public override void OnActionExecuting(ActionExecutingContext filterContext)
 {
    filterContext.HttpContext.Response.Write("OnActionExecuting方法:<br/>");        
     base.OnActionExecuted(filterContext);            
}        

public override void OnActionExecuted(ActionExecutedContext filterContext) 
{            
    filterContext.HttpContext.Response.Write("OnActionExecuted方法<br/>");            
    base.OnActionExecuted(filterContext);        
}        

public override void OnResultExecuting(ResultExecutingContext filterContext)        
{            
     filterContext.HttpContext.Response.Write("OnResultExecuting方法: <br/>");            
     base.OnResultExecuting(filterContext);        
}        

public override void OnResultExecuted(ResultExecutedContext filterContext)        
{            
      filterContext.HttpContext.Response.Write("OnResultExecuted方法:<br/>");            
      base.OnResultExecuted(filterContext);        
}

同時我們建立一個MVC的專案,建立一個MyResultFilter控制器,具體如下:

public class MyResultFilterController : Controller
{
        [MyTestResultFiter]
        public ActionResult Index()
        {
            Response.Write("這裡執行是Action方法,非ViewResult<br/>");
            return View();
        }
}

Index的檢視如下:

@{Layout = null; }

<!DOCTYPE html>

<html> <head>  <title>Index</title> </head>

<body><div>        

<p>ViewResult:這裡是Result的首頁哦~~~~~~</p>    

</div> </body>
</html>

執行結果如下:
這裡寫圖片描述

OnActionExecuting方法和OnResultExecuted方法的執行順序無可爭議,問題在於Action裡面Response.Write的內容是先於OnActionExecuted方法執行的,因此我們可以斷定:OnActionExecuted方法的執行時間實在Action的生命週期之後執行的,Action的生命週期說白了就是大括號{}裡面的程式碼,OnResultExecuting方法實在動作結果之前執行,我們的示例中動作結果輸出的是Index這個檢視,因此會看到OnResultExecuted實在ViewResult之後執行。上圖中示例執行順序

OnActionExecuting>Action>OnActionExecuted>OnResultExecuting>ViewResult>OnResultExecuted。

但是如果只有動作結果過濾器來過濾請求的話,標籤要在每一個動作上做上標籤,顯然是不符合軟體的設計思想的,mvc好在為我們提供了一個全域性的過濾器,全域性過濾器我們需要在全域性檔案Global.asax中進行註冊,我們按照剛才的例子稍加改進一下,來看具體的結果。

Global.asax中註冊全域性過濾器:

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
  filters.Add(new HandleErrorAttribute());
  filters.Add(new MyTestResultFiter() { FilterMessage="標誌全域性過濾器"});
}

同時將MyTestResultFiter過濾器稍作修改如下:

[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]    
public class MyTestResultFiter : ActionFilterAttribute 
{
    public string FilterMessage 
    {
        get;
        set;
    }
    public override void  OnActionExecuting(ActionExecutingContext filterContext) 
    {
        filterContext.HttpContext.Response.Write("OnActionExecuting方法:" + FilterMessage + "<br/>");
        base.OnActionExecuting(filterContext);
    }
    public override void OnActionExecuted(ActionExecutedContext filterContext) 
    {
        filterContext.HttpContext.Response.Write("OnActionExecuted方法" + FilterMessage + "<br/>");
        base.OnActionExecuted(filterContext);
    }
    public override void OnResultExecuting(ResultExecutingContext filterContext) 
    {
        filterContext.HttpContext.Response.Write("OnResultExecuting方法" + FilterMessage + "<br/>");
        base.OnResultExecuting(filterContext);
    }
    public override void OnResultExecuted(ResultExecutedContext filterContext) 
    {
        filterContext.HttpContext.Response.Write("OnResultExecuted方法" + FilterMessage + "<br/>");
        base.OnResultExecuted(filterContext);
    }
}

同時注意將MyTestResultFiter標註為AllowMultiple = true,這樣MyTestResultFiter就可以執行在ControllerAction上都起作用。否則執行執行Action上的MyTestResultFiter特性。執行結果如下:
這裡寫圖片描述

但是還有一點我們需要注意的是Controller它本身也是一個過濾器,我們來看Controller的定義:

public abstract class Controller : ControllerBase, IActionFilter, IAuthorizationFilter, IDisposable, IExceptionFilter, IResultFilter

Controller也實現了mvc的四大過濾器的介面,因此我們來測試一下這個Controller過濾器的執行順序是什麼?我們在MyResultFilter裡面稍作修改:

[MyTestResultFiter(FilterMessage="這裡是Controller的:")]
public class MyResultFilterController : Controller 
{
    [MyTestResultFiter(FilterMessage = "這裡是Action的:")]
            public ActionResult Index() 
    {
        Response.Write("這裡執行是Action方法,非ViewResult<br/>");
        return View();
    }
}

最終執行的效果如下:
這裡寫圖片描述

因此整個過濾器的執行順序大致如下:全域性過濾器>Controller上標記的特性過濾器>Action上標記的特性過濾器,裡面的四種方法的執行順序大家看完之後應該明白了吧~~~

相關文章