ASP.NET Web API Controller 是怎麼建成的

來源:互聯網
上載者:User

標籤:des   style   blog   http   color   使用   os   io   

先看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 響應訊息。訊息處理流程如下:

  1. 當用戶端對伺服器發出的 HTTP 要求開始進入 ASP.NET Web API 架構時,該 HTTP 要求訊息會被封裝成HttpRequestMessage對象,並且進入圖中最頂端「裝載」方塊的HttpServer(web 裝載)或HttpSelfHostServer(自我裝載)。接著該訊息便流入管線的下一個階段,直到整個訊息流程處理完畢,會得到一個代表 HTTP 響應訊息的 HttpResponseMessage對象,並將此對象的訊息內容傳回用戶端。
  2. HttpRequestMessage對象進入「訊息處理常式」管線。在此階段,HTTP 訊息行經數個訊息處理常式(message handlers),並且在返回 HTTP 響應訊息時以相反的順序執行。
  3. 在各個訊息處理常式之後,HTTP 要求訊息接著會傳遞給HttpControllerDispatcher,並且由這個對象來建立 Web API controller,然後將 HTTP 要求傳遞給 controller 對象(圖中標示「(A) 建立 controller」的步驟)。
  4. Controller 會先決定目標動作方法(即圖中標示「(B) 選擇 action」的步驟),然後呼叫它。動作方法將負責產生響應內容,之後便依前述管線流程的反方向沿路返回。

以上便是 Web API HTTP 訊息管線的大致處理流程。

 

Web API Controller 是怎樣建成的?

剛才只說明了 Web API HTTP 訊息管線的大致處理流程,而欲注入相依對象至 controller 類別的建構函式,或從中動些手腳來改變預設行為,必得瞭解 Web API 架構建立 controller 的內部過程。本節將進一步說明其中的複雜環節,其中會反覆提及多個抽象介面,第一次閱讀時可能略感吃力,並難免心生疑惑,但等到實際寫過、跑過一遍後面的範常式序,再回頭來看這一節的說明,整個拼圖應該就會漸漸明朗了。

剛才提到,HttpControllerDispatcher會建立目標 controller 對象,亦即先前 ASP.NET Web

API 管線架構圖中標示「(A) 建立 controller」的步驟。此步驟其實包含兩件工作:

  1. 解析目標 controller。亦即決定該使用哪一個 controller 類別。
  2. 建立目標 controller 類別的執行個體,並將 HTTP 要求(HttpRequestMessage對象)傳遞給它,以便由 controller 進行後續處理。

首先,「解析目標 controller」的工作主要是從應用程式的 DLL 組件中尋找所有可用的 controller 類別,再從中選擇一個與當前 HTTP request 匹配的。其處理邏輯如所示:

說明:

  • 圖中下方的IAssembliesResolver對象的GetAssemblies方法將提供應用程式的組件列表,並由IHttpControllerTypeResolver對象的GetControllerTypes方法取得可用的 controller 類別清單。
  • IHttpControllerSelector負責決定要選擇哪一個 controller 類別,然後返回一個包含其型別資訊的HttpControllerDescriptor對象給HttpControllerDispatcher。

 從確定目標 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 章。

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.