系列目錄
Action的定位
再次回到Controller的ExecuteCore方法,回到action調用的入口:
if (!ActionInvoker.InvokeAction(ControllerContext, actionName))
這裡的ActionInvoker是個IActionInvoke,它無疑是負責了所有action的調用邏輯,MVC中預設實現這個介面的是ControllerActionInvoke。可以想象ControllerActionInvoke面臨的第一個問題是如何找到與actionName對應的action。
首先,並不是所有的action都合法,需要符合下麵條件:
1、Public,非static
2、非Controller或其基類定義的方法,比如ToString(),GetHashcode()
3、不能是特殊名字System.Reflection.MethodBase的IsSpecialName標誌,例如建構函式,屬性包裝器,事件封裝器
4、具有泛型參數的方法儘管會被認為是action,但架構試圖執行這樣的action時會只是拋出異常。
其次,MVC為action的尋找過程設計了兩種“選取器”
- ActionNameSelectorAttribute
- ActionMethodSelectorAttribute
如果對此比較迷茫的話,看了他們的派生特性,你也許就明白了:
我們常用ActionNameAttribute來“偽裝”;用HttpPostAttribute或HttpGetAttribute來說明某個action符合的特定的http行為;用NoAction隱藏我們不想“暴露給url”的方法…其實這些行為的原理便是利用MVC為我們提供的action選擇的機制。下面這張圖說明了這個過程的完成邏輯:
ContollerActionInvoker.InvokeAction在內部建立一個ReflectedControllerDescriptor,並調用其FindAction方法,這個對象的FindAction負責調用一個ActionMethodSelector對象實現上述邏輯,並在最後返回一個ReflectedActionDescriptor。ActionMethodSelector對象故名思意,原理上用反射執行上述過程,執行的結果要麼返回一個MethodInfo,要麼返回null,要麼拋出異常。ReflectedControllerDescriptor對傳回值判斷,如果是null,則也返回null;如果是MethodInfo,則將其封裝成ReflectedActionDescriptor返回。對於外面的InvokeAction方法來說只要ReflectedControllerDescriptor返回的ReflectedActionDescriptor為空白就返回false,否則繼續。Controller負責對返回false的情況調用HandleUnknownAction,該方法預設產生404錯誤,我們可以重寫它。
在回過頭來看看的邏輯,不難得到這樣一個事實:ActionNameSelectorAttribute優先於ActionMethodSelectorAttribute,ActionMethodSelectorAttribute優先於沒有ActionMethodSelectorAttribute特性的方法。
更多關於這部分源碼的細節,可以參考:通過原始碼研究ASP.NET MVC中的Controller和View(六)
MVC的內建過濾器
當ActionDescriptor(ReflectedActionDescriptor)返回後,ContollerActionInvoker開始執行action,但是在執行action前還有一些額外的步驟,那就是過濾。以下四個是MVC內建的過濾介面:
- IActionFilter
- IAuthorizationFilter
- IExceptionFilter
- IResultFilter
這四個Filter會被ControllerActionInvoker架構綜合考量,下面的虛擬碼說明了ControllerActionInvoker處理他們的邏輯順序:
try{//依次執行IAuthorizationFilterRun each IAuthorizationFilter's OnAuthorization() method//所有的IAuthorizationFilter都返回null而不是ActionResultif(none of the IAuthorizationFilters cancelled execution){Run each IActionFilter's OnActionExecuting() methodRun the action method//注意到這裡按照反轉順序進行Run each IActionFilter's OnActionExecuted() method (in reverse order)Run each IResultFilter's OnResultExecuting() methodRun the action result//注意到這裡按照反轉順序進行Run each IResultFilter's OnResultExecuted() method (in reverse order)}//有IAuthorizationFilter返回ActionResultelse{Run any action result set by the authorization filters}}catch(exception not handled by any action or result filter){//注意到IExceptionFilter處理的異常只在這個try catch塊中Run each IExceptionFilter's OnException() methodRun any action result set by the exception filters}
需要注意的事項,在代碼中都已經給出注釋,在後面一節中,將討論其中的某些細節。
MVC中與這四個介面相關的特性如下:
我們熟悉的有Authorize,OutputCache,ChildAction等。曾經,對於這些形形色色的Attribute,我都不能很好的理解和歸類,現在總算是找它們各自的歸宿了。
下一節,將針對這四個過濾器介面深入討論一些細節問題。
勞動果實,轉載請註明出處:http://www.cnblogs.com/P_Chou/archive/2010/12/01/details-asp-net-mvc-07.html