您好,登錄后才能下訂單哦!
ASP.NET Web API 控制器創建過程(二)
前言
本來這篇隨筆應該是在上周就該寫出來發布的,由于身體跟不上節奏感冒發燒有心無力,這種天氣感冒發燒生不如死,也真正的體會到了什么叫病來如山倒,病去如抽絲。這兩天狀態才好了一點,讓我理解了什么才是革命的本錢,希望大家也多保重身體。
好了,還是回歸主題,對于上一篇的內容講解的只是ASP.NET Web API控制器創建過程中的一個局部知識,在接著上篇內容講解的之前,我會先回顧一下上篇的內容,并且在本篇里進行整合,讓我們要看到的是一個整個的創建過程。
ASP.NET Web API 控制器創建、激活過程
l ASP.NET Web API 控制器創建過程(一)
l 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(通過反射)。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。