Agenda
- 前言
- InvokeAction方法
- 在Controller類別中 重要方法ExecuteCore()
- 取得執行的ActionInvoker(AsyncControllerActionInvoker)
- ControllerActionInvoker呼叫InvokeAction方法
- Asp.net AOP機制揭密(Filter)
- FilterProviderCollection的GetFilters方法(額外註冊過濾器)
- 小結
前言
前面介紹完 Asp.net MVC解析器和IOC容器之間關係
本篇要介紹Controller如何去呼叫使用的Action方法.
ExecuteCore是ControllerBase類別提供給Controller來實作Hook方法.
我有做一個可以針對於Asp.net MVC Debugger的專案,只要下中斷點就可輕易進入Asp.net MVC原始碼.
InvokeAction方法
之前說到MVC呼叫ControllerBase.Execute方法,其中這個方法做了幾件事情
VerifyExecuteCalledOnce方法對於同步請求做一個防呆機制(不允許同一時間處理相同請求)Initialize初始化資料- 呼叫
ExecuteCore抽象方法(由Controller實現)
在ControllerBase會InvokeAction來執行並叫Action方法.
1 | public abstract class ControllerBase : IController{ |
在Controller類別中 重要方法ExecuteCore()
在上面有說到ExecuteCore抽象方法由Controller來實現
1 | protected override void ExecuteCore() |
這個方法會呼叫GetActionName透過Route規則解析Action名稱,在呼叫ActionInvoker的InvokeAction方法判斷呼叫Action方法是否呼叫成功.
取得執行的ActionInvoker(AsyncControllerActionInvoker)
ActionInvoker是一個在Controller屬性,一開始先判斷_actionInvoker是否為null如果是就會建立一個IActionInvoker物件.
1 | public IActionInvoker ActionInvoker |
讓我們來看看CreateActionInvoker方法如何建立IActionInvoker物件吧!
1 | protected virtual IActionInvoker CreateActionInvoker() |
透過CreateActionInvoker方法來取得執行IActionInvoker,取得順序如下
- 透過解析器找尋是否有實現
AsyncActionInvokerFactory物件 - 透過解析器找尋是否有實現
IActionInvokerFactory物件 - 透過解析器
IAsyncActionInvoker物件 - 透過解析器
IActionInvoker物件 - 建立一個
AsyncControllerActionInvoker物件
所以預設是使用AsyncControllerActionInvoker這個非同步ActionInvoker
ControllerActionInvoker呼叫InvokeAction方法
ControllerActionInvoker是同步版本AsyncControllerActionInvoker是非同步版本
使用InvokeAction方法來調用我們使用的Action方法,並透過執行完回傳Bool辨別調用是否成功.
取得 ControllerDescriptor & ActionDescriptor
在InvokeAction方法一開始會先取得ControllerDescriptor和ActionDescriptor兩個物件(把得到資訊進行封裝).
1 | ControllerDescriptor controllerDescriptor = GetControllerDescriptor(controllerContext); |
GetControllerDescriptor取得Controller封裝後的資訊(同步使用ReflectedControllerDescriptor).- 取得
ActionDescriptor(ReflectedActionDescriptor)並在執行Execute方法要靠他來執行Action方法
FindAction返回一個ActionDescriptor.
這個物件對於日後呼叫Action方法有很重要地位.
1 | public override ActionDescriptor FindAction(ControllerContext controllerContext, string actionName) |
ReflectedControllerDescriptor利用反射取得要執行的Method資料(MethodInfo),並封裝到ReflectedActionDescriptor類別中.
Asp.net AOP機制揭密(Filter)
取得完ActionDescriptor物件後,會先判斷actionDescriptor是否建立成功,如果建立成功就會呼叫GetFilters方法取得目前所有註冊過濾器.
1 | if (actionDescriptor != null) |
呼叫GetFilters方法會取得Asp.net MVC註冊的所有Filter物件(提供一個織布點方便開發人員彈性做擴充).
1 | private Func<ControllerContext, ActionDescriptor, IEnumerable<Filter>> _getFiltersThunk = FilterProviders.Providers.GetFilters; |
_getFiltersThunk是一個委派物件,預設使用FilterProviders.Providers.GetFilters
FilterProviderCollection這個集合對象在前一篇Asp.net MVC DI有介紹到,對於DI做一個擴充點(CombinedItems)屬性從容器中取得有對於IFilterProvider註冊Filter物件.
預設使用FilterProviders(FilterProviderCollection)
MVC會透過FilterProviders.Providers取得預設使用FilterProvider,透過以下三個地方取得
GlobalFilterCollection(在Global擴充)ControllerInstanceFilterProvider(Controller自行Override)FilterAttributeFilterProvider(提供Attribute註冊最常用)
1 | /// <summary> |
FilterAttributeFilterProvider(取得標籤的Filter)
IFilterProvider介面提供一個方法GetFilters取得過濾器集合
1 | public interface IFilterProvider |
從程式碼得知
GetControllerAttributes從Controller取得,所有繼承FilterAttribute標籤.GetActionAttributes從Action取得,所有繼承FilterAttribute標籤.
我們最常把
Filter寫在Controller或Action上就是透過FilterAttributeFilterProvider的GetFilters方法取得標籤並封裝成Filter物件返回,使用.
FilterProviderCollection的GetFilters方法(額外註冊過濾器)
GetFilters方法利用CombinedItems取得所有IFilterProvider物件,再利用GetFilters方法逐一取得註冊Filter物件.
1 | public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) |
小結
今天就先分享執行Action前執行動作,在InvokeAction方法中有兩個很重要的物件.
ControllerDescriptor封裝Controller主要使用資訊ActionDescriptor封裝Action主要使用資訊,並利用裡面的Execute方法執行Action.
另外一點我們也了解Asp.net MVC如何實現AOP編寫方式,透過Attribute + Filter,讓系統更有擴展性.
目前Filter類別跟ControllerActionInvoker類別UML圖關係如下
下篇會跟大家分享MVC Filter是在哪裡被呼叫且裡面Filter參數是如何被產生的.
__此文作者__:Daniel Shih(石頭)
__此文地址__: https://isdaniel.github.io/ithelp-day15/
__版權聲明__:本博客所有文章除特別聲明外,均採用 CC BY-NC-SA 3.0 TW 許可協議。轉載請註明出處!