先看ASP.NET Web API 訊息管線:

註:為了避免圖片太大以至于超過版面,上圖中的「HTTP 訊息處理程序」區塊省略了 HttPRoutingDispatcher 處理路由分派的部分。「控制器」區塊則省略了篩選條件(filter)的處理細節。微軟網站有提供一份比較完整的 Web API 訊息處理流程圖,網址是 http://www.microsoft.com/en-us/download/details.aspx?id=36476。
此訊息管線架構圖分為三層,由上至下,分別是裝載(Hosting)、訊息處理程序(Message Handlers)、以及控制器(Controller)。圖中的紅色實心箭頭代表 HTTP 請求訊息,虛線箭頭代表 HTTP 響應消息。訊息處理流程如下:
以上便是 Web API HTTP 訊息管線的大致處理流程。
Web API Controller 是怎樣建成的?
剛才只說明了 Web API HTTP 訊息管線的大致處理流程,而欲注入相依對象至 controller 類別的建構函式,或從中動些手腳來改變預設行為,必得了解 Web API 框架建立 controller 的內部過程。本節將進一步說明其中的復雜環節,其中會反復提及多個抽象接口,第一次閱讀時可能略感吃力,并難免心生疑惑,但等到實際寫過、跑過一遍后面的范例程序,再回頭來看這一節的說明,整個拼圖應該就會漸漸明朗了。
剛才提到,HttpControllerDispatcher會建立目標 controller 對象,亦即先前 ASP.NET Web
API 管線架構圖中標示「(A) 建立 controller」的步驟。此步驟其實包含兩件工作:
首先,「解析目標 controller」的工作主要是從應用程序的 DLL 組件中尋找所有可用的 controller 類別,再從中選擇一個與當前 HTTP request 匹配的。其處理邏輯如下圖所示:

說明:
從確定目標 controller 型別之后,到建立完成 controller 實例的過程中,還有經過一些核心標準接口所提供的擴充點。底下再用一張 UML 活動圖搭配 Web API 原始碼的方式來解構其內部處理過程。

說明如下(與上圖中的數字編號對應):
(1) HttpControllerDispatcher透過IHttpControllerSelector對象的SelectController方法來取得目標 controller 型別信息,這型別信息是包在一個HttpControllerDescriptor 對象里。
(2) HttpControllerDispatcher接著呼叫HttpControllerDescriptor對象的CreateController 方法,而該方法又會去呼叫ServicesContainer對象的GetHttpControllerActivator方法來取得IHttpControllerActivator對象。以下程序片段摘自 Web API 原始碼,涵蓋了此步驟至下一步驟的部分邏輯:
// HttpControllerDescriptor 類別的 CreateController 方法。public virtual IHttpController CreateController(HttpRequestMessage request) { IHttpControllerActivator activator = Configuration.Services.GetHttpControllerActivator(); IHttpController instance = activator.Create(request, this, ControllerType); return instance;}(3) 取得IHttpControllerActivator對象之后,便接著呼叫它的Create方法,而此方法會呼叫自己的GetInstanceOrActivator方法,以便取得 controller 實例。以下程序片段摘自DefaultHttpControllerActivator類別的原始碼,我把錯誤處理以及快取機制的部分拿掉,并加上了中文批注:
// DefaultHttpControllerActivator 類別的 Create 方法(重點摘錄)public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType){ Func<IHttpController> activator; IHttpController controller = GetInstanceOrActivator(request, controllerType, out activator); if (controller != null) { // 註冊至 Web API 框架的 dependency resolver // 已經建立此 controller 型別的執行個體。 return controller; // 那就直接使用此物件。 } // 目標 controller 物件尚未建立 return activator(); // 那就用 GetInstanceOrActivator 方法傳回的委派來建立物件}(4) IHttpControllerActivator對象的GetInstanceOrActivator方法會呼叫HttpRequestMessage 的擴充方法GetDependencyScope來取得與當前 request 關聯的IDependencyScope對象(其實就是個 Service Locator),并利用它的GetService方法來取得 controller 對象。若 GetService方法并未傳回 controller 對象,而是傳回null(代表無法解析服務型別),則退而求其次,改用型別反射(reflection)機制來建立 controller 對象。一樣搭配原始碼來看:
// 摘自 DefaultHttpControllerActivator.csprivate static IHttpController GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, out Func<IHttpController>> activator){ // 若 dependency scope 有傳回 controller 對象,便使用它。 IHttpController instance = (IHttpController)request.GetDependencyScope().GetService(controllerType); if (instance != null) { activator = null; return instance; } // 否則,建立一個委派來創建此型別的實例。 activator = TypeActivator.Create<IHttpController>(controllerType); return null;}其中的request.GetDependencyScope()就是對應到剛才說的「呼叫HttpRequestMessage 的擴充方法 GetDependencyScope 來取得與當前 request 關聯的 IDependencyScope 對象。」而這里實際取得的IDependencyScope對象會是 Web API 框架提供的預設實作: EmptyResolver。從類別名稱可知,這類別其實啥事也沒做——它的GetService方法一律傳回null。因此,在預設情況下,Web API 框架會一律使用型別反射(reflection)機制來建立 controller 對象,而這也就是為什么我們的 controller 類別一定要有預設建構函式(default constructor)的緣故。
大致上,controller 對象就是這么建成的。
本文摘自《.NET 相依性注入》一書的第 5 章。
新聞熱點
疑難解答