ASP.NET沒有魔法——ASP.NET MVC 過濾器(Filter)

上一篇文章介紹了使用Authorize特性實現了ASP.NET MVC中針對Controller或者Action的授權功能,實際上這個特性是MVC功能的一部分,被稱爲過濾器(Filter),它是一種面向切面編程(AOP)的實現,本章將從以下幾個方面來介紹ASP.NET MVC中的過濾器。

  ● ASP.NET MVC 中的過濾器及其類型
  ● ASP.NET MVC 中常用的過濾器
  ● ASP.NET MVC 過濾器的應用方法
  ● ASP.NET MVC Action方法的調用與Filter的執行
  ● ASP.NET MVC 過濾器的創建與獲取
  ● ASP.NET MVC Action及Result過濾器的管道執行

ASP.NET MVC中的過濾器及其類型

  在之前的Entity Framework文章中介紹了EF自帶的攔截器(interceptors)功能,ASP.NET MVC中的過濾器也和攔截器一樣是一種面向切面(AOP)的編程方式,是一種不修改源代碼的前提下對應用程序進行拓展的編程方式。一般AOP用來處理日誌記錄、性能統計、安全控制、事務處理、異常處理等不會對原有業務數據進行修改的功能。
  ASP.NET MVC中把過濾器分爲以下幾類,每一類都是通過一個對應的接口定義的:
  ● 身份驗證過濾器(IAuthenticationFilter):這個過濾器是在MVC5中加入的,它是所有過濾器中優先級最高的,使用身份驗證過濾器可以爲Action、Controller或者所有的Controller添加身份驗證邏輯。身份驗證過濾器的核心在於根據請求信息創建一個Principal對象(注:使用Identity的身份驗證功能實際上也是創建一個Principal對象),以下是IAuthenticationFilter的定義:

  

  其中身份驗證上下文有一個IPrincipal的屬性:

  

  ● 授權過濾器(IAuthorizationFilter):授權過濾器用來處理Controller以及Action的訪問限制。
  ● Action方法過濾器(IActionFilter):Action過濾器可用於在Action方法執行前和執行後添加邏輯。
  ● 結果過濾器(IResultFilter):結果過濾器可以在結果執行前和執行後添加邏輯。(注:ASP.NET MVC中的Action返回結果爲ActionResult類型,該抽象類型定義了一個執行方法ExecuteResult,結果的執行實際上是對返回結果的處理)

  

  比如FileResult的執行實際上是在Http響應頭中添加了適當的參數然後將文件的二進制數據寫到了響應體中,相當於文件的下載功能。

  

  更多結果執行內容會在後續文章中介紹。

  ● 異常過濾器(IExceptionFilter):異常過濾器就是Action方法在執行的過程中拋出異常時,用來添加異常處理邏輯的過濾器。

ASP.NET MVC 中常用的過濾器

  上面介紹了過濾器的類別,現在介紹一下每一個類別下常用的過濾器有哪些:
  ● 身份驗證過濾器(IAuthenticationFilter):由於身份驗證過程可以使用Identity等成熟組件來完成,所以身份驗證過濾器暫時沒有找到適合的可以用的過濾器。如果系統有需求可自定義。
  ● 授權過濾器(IAuthorizationFilter):
    ○ Authorize:基於用戶名、角色的用戶授權。
    ○ RequireHttps:基於Https的訪問授權。
    ○ ValidateInput:ASP.NET MVC在執行前會驗證請求信息中是否包含HTML等不合法信息以避免XSS攻擊,但是有的時候需求就是要提交HTML數據,在提交這些數據時可以使用該過濾器將EnableValidation設爲false,MVC將跳過數據驗證。
    ○ ValidateAntiForgeryToken:該過濾器可以對HtmlHelper的AntiForgeryToken方法生成防僞令牌進行校驗,以避免CSRF跨站僞造攻擊。
  ● Action過濾器(IActionFilter):一般根據需求自定義實現。
  ● 異常過濾器(IExceptionFilter):
    ○ HandleError:用於處理Action方法拋出的異常(默認的MVC模板會添加一個全局HandleError過濾器)。

  另外還需要注意的是ASP.NET MVC中的Controller實際上也是一個過濾器,因爲Controller基類實現了所有過濾器接口:

  

  所以如果某一Controller中有特殊的處理需求,無需定義過濾器,在Controller中實現重載對應過濾器的方法即可:

  

ASP.NET MVC 過濾器的應用方法 

  ASP.NET MVC中的過濾器可以通過以下幾種方法使用:
  1. 通過特性的方式在Controller以及Action上標記使用,但是要注意的是以特性方式使用的過濾器除了實現對應的過濾器接口外還需要將其封裝爲一個.Net特性並實現IMvcFilter接口,最爲方便的是直接繼承FilterAttribute類型實現,如:

  

  2. 通過全局過濾器表添加過濾器,這樣添加的過濾器會對所有Controller的Action方法生效。

  

  3. 在Controller類型中通過重載對應過濾器方法的方式實現,上面說明了Controller本身就是一個實現了所有過濾器的類型。

ASP.NET MVC Action方法的調用與Filter的執行

  過濾器是在Action方法執行的過程中調用執行的,所以首先要了解Action的執行過程,在之前的文章中介紹了Controller的創建與執行《ASP.NET沒有魔法——ASP.NET MVC Controller的實例化與執行》,而這裏就基於該文章,來對Action的執行過程進行介紹,Controller的執行是通過Controller類型的ExecuteCore方法完成的:

  

  而從代碼中也可以看到Controller的執行實際上是通過ActionInvoker根據Action的名稱來調用Action方法的執行,在ASP.NET MVC中默認使用一個名爲 AsyncControllerActionInvoker的異步Action調用器:

  

  它除了異步功能外還繼承了同步的ControllerActionInvoker類型,異步主要是爲了提高請求處理的吞吐量,這裏將使用同步版本的代碼進行Action與Filter執行介紹。

  ControllerActionInvoker:

   

  從代碼定義中可以看出以下幾點:
  1. 它的核心方法是InvokeAction,它處理了所有的過濾器、Action方法的調用處理邏輯。
  2. GetFilters方法,它用於獲取所有相關的過濾器。
  3. InvokeActionMethodWithFilters、InvokActionResultWitherFilters、InvokeAuthenticationFilters、InvokeAuthenticationFiltersChallenge、InvokeAuthorizationFilters、InvokeExceptionFilters等相關方法就是用來調用對應類型的過濾器執行的方法。
  這裏通過源碼分析的方式來介紹過濾器在ActionInvoker的執行過程:

 View Code

  通過對上面代碼的分析得出以下幾個結論:
  1. 通過Controller上下文及Action的信息找到真實的Action方法後,獲取所有過濾器。
  2. 先執行身份驗證過濾器。
  3. 通過身份驗證過濾器後執行授權過濾器。
  4. 授權過濾器通過後,執行Action過濾器及Action方法。
  5. 執行Result過濾器及Result。

ASP.NET MVC 過濾器的創建與獲取

  根據上面的介紹知道了可以通過全局過濾器、特性標記以及重載Controller過濾器方法這三種方式來應用過濾器的,那麼在執行過程中是如何通過ActionInvoker的GetFilters方法創建和獲取它們的呢?
  ● 過濾器提供器(FilterProvider):ASP.NET MVC中有一個過濾器提供器的概念和實際對象,它有三種實現分別對應上述的三種應用方式:
    ○ GlobalFilterCollection:用於保存全局過濾器實例,可以直接通過它添加和獲取過濾器實例,通過它創建的過濾器的Scope爲Gobal,創建時可以通過Order參數來決定全局過濾器的執行順序:

  

    ○ FilterAttributeFilterProvider:過濾器特性提供器,通過查找Controller以及Action上的特性來創建過濾器,根據特性標記位置將Scope分爲Controller以及Action,在應用特性時可以設置特性的Order屬性來決定過濾器的執行順序:

    

    ○ ControllerInstanceFilterProvider:控制器實例過濾器提供器,它用於獲取當前Controller實例的過濾器,並且過濾器的Scope爲First:

    

  ● 過濾器提供器集合(FilterProviderCollection):它包含了上述的所有過濾器提供器,ActionInvoker就是通過它來獲取所有相關過濾器的:

  

  FitlerProviderCollection獲取過濾器時通過以上三種提供器獲取所有相關的過濾器並根據Scope以及Order對過濾器進行排序,以決定過濾器執行順序。

ASP.NET MVC Action及Result過濾器的管道執行

  在Action和Result過濾器的定義中都有兩個方法,分別是OnXXXExecuting以及OnXXXExecuted,它們對應Action或者Reuslt執行前和執行後。當一個Action上存在多個Action或者Result過濾器時就會形成一個過濾器管道,其執行方式如下圖所示:

  

小結

  本文除了介紹ASP.NET MVC的過濾器功能及常用的過濾器外,還通過代碼的形式分析了它創建與執行的過程。在一般的項目中使用ASP.NET MVC自帶的過濾器就可以滿足需求,如授權、錯誤處理等,但過濾器作爲ASP.NET MVC中的一種重要的AOP拓展方式,合理的運用過濾器可以實現,如日誌記錄、性能分析、Action的事務執行(http://blog.gauffin.org/2012/06/how-to-handle-transactions-in-asp-net-mvc3/,這篇文章就利用Action過濾器實現了數據庫的事務)等等功能,並且可以靈活的在不影響原有代碼邏輯的情況下對系統進行拓展。

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