標籤:asp.net web api apicontroller .net
ASP.NET Web API 控制器建立過程(二)
前言
本來這篇隨筆應該是在上周就該寫出來發布的,由於身體跟不上節奏感冒發燒有心無力,這種天氣感冒發燒生不如死,也真正的體會到了什麼叫病來如山倒,病去如抽絲。這兩天狀態才好了一點,讓我理解了什麼才是革命的本錢,希望大家也多保重身體。
好了,還是迴歸主題,對於上一篇的內容講解的只是ASP.NET Web API控制器建立過程中的一個局部知識,在接著上篇內容講解的之前,我會先回顧一下上篇的內容,並且在本篇裡進行整合,讓我們要看到的是一個整個的建立過程。
ASP.NET Web API 控制器建立、啟用過程
- ASP.NET Web API 控制器建立過程(一)
- ASP.NET Web API 控制器建立過程(二)
建立、啟用過程
圖1
在前面的篇幅中我們說過APIController是由HttpControllerDispatcher類型來建立的,這隻是表面上的,圖1中顯示的就是控制器建立的整個過程了,我們先來回顧一下上一篇所講的,不然會覺得不連貫,在回顧的同時也會對圖1進行講解。
首先我們來分解圖1,可以把圖1中分為兩個部分,
第一個部分就是HttpConfiguration類型所表示的部分。2
圖2
先來解釋一下HttpConfiguration部分,在HttpConfiguration類型中有兩個屬性,第一個是ServicesContainer類型的屬性Services,第二個就是IDependencyResolver類型的屬性DependencyResolver,對於Services屬性的類型在上篇中我也說過了,就是一個IoC容器,從HttpConfiguration類型角度來看就是一個依賴注入到HttpConfiguration中的IoC容器,對於DependencyResolver屬性來說也差不多就是這個意思了。
只不過Services這個容器中存放的大多都是ASP.NET Web API架構中做一些基礎工作的類型。
就好像上篇中說到的,在ASP.NET Web API架構中載入控制器所在程式集的時候我們就是使用自訂的工作項目替換掉了Services容器中的預設工作項目:
selfHostServer.Configuration.Services.Replace(typeof(IAssembliesResolver), newCustomAssembliesResolver.LoadSpecifiedAssembliesResolver());
這裡從圖2中可以看出預設的DefaultAssembliesResolver類型來執行這項工作的。
到這裡也就是上個篇幅中的主要內容了。下面我們還是繼續分解圖1,上面說了第一部分了下面來看第二部分,第二個部分就是HttpControllerDispatcher類型到APIController類型的產生過程,也就是圖1了。
首先我們的ASP.NET Web API架構會從HttpConfiguration中的Services容器中擷取一個ControllerSelector(控制器選取器),這個控制器選取器呢對應的類型大家從圖2中也可以看到,圖1中也有,很明了。
那麼ControllerSelector主要幹什麼呢?肯定是選擇控制器阿,當然了根據請求選擇相應的控制器是主要功能,次要功能是啥?次要功能是組建控制器緩衝,不然從哪選阿對不。在ASP.NET MVC架構中控制器緩衝是存在xml檔案中的,現在很好奇在ASP.NET Web API架構中控制器緩衝是什麼樣的儲存方式呢?
我們就來看一下控制器選取器的次要功能。
控制器選取器次要功能
首先我們先說明一下緩衝的類型為ConcurrentDictionary<string, HttpControllerDescriptor>類型,就是一個一一對應的鍵值隊,string表示著控制器名稱,而HttpControllerDescriptor表示著對應控制器的控制器描述類型,這個類型很重要稍後再說,我們先要瞭解ConcurrentDictionary<string, HttpControllerDescriptor>緩衝的由來。
首先在我們控制器選取器執行個體化的時候,在控制器選取器的建構函式中已經使用了消極式載入技術對控制器緩衝進行了建立,具體的建立過程可以在圖1看到,是由DefaultAssembliesResolver類型(或者是我們自訂的工作項目)載入指定的程式集,並且交由DefaultHttpControllerTypeResolver類型根據ASP.NET Web API架構中預設的搜尋過濾條件返回載入程式集中的所有合格控制器類型(ControllerTypes),來看樣本。
所用項目結構還是上個篇幅的樣本:
圖3
圖4
在圖4中我們額外定義了一些控制器類型,然後在SelfHost端定義如下範例程式碼:
代碼1-1
staticvoidWriterControllerTypeMessage(HttpSelfHostServerselfHostServer) { ICollection<Type>types=selfHostServer.Configuration.Services.GetHttpControllerTypeResolver().GetControllerTypes(selfHostServer.Configuration.Services.GetAssembliesResolver()); foreach (Typetypeintypes) { Console.WriteLine(type.Namespace+"_______"+type.Name); } }
並且在註冊端調用此靜態函數:
using (HttpSelfHostServerselfHostServer=newHttpSelfHostServer(selfHostConfiguration)) { selfHostServer.Configuration.Routes.MapHttpRoute( "DefaultApi", "api/{controller}/{id}", new { id=RouteParameter.Optional }); selfHostServer.Configuration.Services.Replace(typeof(IAssembliesResolver), newCustomAssembliesResolver.LoadSpecifiedAssembliesResolver()); WriterControllerTypeMessage(selfHostServer); selfHostServer.OpenAsync(); Console.WriteLine("伺服器端服務監聽已開啟"); Console.Read(); }
結果5:
圖5
在我們擷取了ControllerTypes過後了,ASP.NET Web API架構中有個HttpControllerTypeCache類型的對象就藏不住了,之前的一些操作都是由HttpControllerTypeCache類型去處理的,而在HttpControllerTypeCache擷取了ControllerTypes過後就要做一個很重要的工作了,就是對ControllerTypes進行分組操作最後返回一個Dictionary<string, ILookup<string, Type>>類型的對象,就拿上面的樣本來說吧,最後經過分組後的Dictionary<string, ILookup<string, Type>>類型值應該是:
Writer-->NameSpaceControllerOne->WriterController
NameSpaceControllerTwo->WriterController
Read-->NameSpaceControllerOne->ReadController
WriterAndRead-->NameSpaceControllerThree->WriterAndReadController
Product-->WebAPIController->ProductController
這個時候的值並不是最終的緩衝類型,而是通過我們的控制器選取器根據HttpControllerTypeCache類型所產生的Dictionary<string,ILookup<string, Type>>類型值來產生ConcurrentDictionary<string, HttpControllerDescriptor>緩衝類型,還是根據上面的樣本,我們看一下最後產生的緩衝類型值。
修改1-1如下範例程式碼:
代碼1-2
staticvoidWriterControllerTypeMessage(HttpSelfHostServerselfHostServer) { ICollection<Type>types=selfHostServer.Configuration.Services.GetHttpControllerTypeResolver().GetControllerTypes(selfHostServer.Configuration.Services.GetAssembliesResolver()); foreach (Typetypeintypes) { Console.WriteLine(type.Namespace+"_______"+type.Name); } //Dictionary<string,ILookup<string, Type>> controllertypecache = types.GroupBy<Type,string>(t => t.Name,StringComparer.OrdinalIgnoreCase).ToDictionary<IGrouping<string,Type>, string, ILookup<string, Type>> // (g => g.Key, // g => g.ToLookup<Type,string>(t => (t.Namespace ?? string.Empty),StringComparer.OrdinalIgnoreCase), StringComparer.OrdinalIgnoreCase); //foreach(var value in controllertypecache) //{ // foreach (var val in value.Value) // { // } //} IDictionary<string, HttpControllerDescriptor>mapping=selfHostServer.Configuration.Services.GetHttpControllerSelector().GetControllerMapping(); foreach (varmeginmapping) { Console.WriteLine("ControllerName:"+meg.Key+".ControllerTypeName:"+meg.Value.ControllerType.Name); } }
結果6:
圖6
(在代碼1-2中注釋掉的部分就是可以查看對ControllerTypes進行分組操作返回Dictionary<string, ILookup<string, Type>>類型的值)。
控制器選取器主要功能
次要功能看完之後,主要功能想必大家也是很明了吧,在有了控制器緩衝對象過後,控制器選取器則會根據HttpRequestMessage對象中的路由資料對象擷取控制器名稱,然後從緩衝中擷取到對應的HttpControllerDescriptor類型執行個體。
具體產生工作
在擷取到了HttpControllerDescriptor類型執行個體過後產生IHttpController的工作就變得很簡單了,還是從HttpConfiguration中的Services容器中獲得對應的負責控制器產生啟用的工作項目,在圖1中可以明確的看出是DefaultHttpControllerActivator類型,在DefaultHttpControllerActivator類型工作的時候它會從HttpConfiguration中擷取DependencyResolver屬性對應的容器,如果這裡的情況不滿足才會調用後面的TypeActivator來產生啟用IHttpController(通過反射)。
金源
出處:http://blog.csdn.net/jinyuan0829
本文著作權歸作者和CSDN共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面