我們在開發完Asp.Net WebAPI程序后,可以使用WebHost寄宿方式或者SelfHost寄宿方式來部署Asp.Net WebAPI。所謂WebHost寄宿就是通過Asp.Net來實現;所謂SelfHost就是可以通過控制台、WinForm、WPF等方式寄宿。下面我們通過簡單的例子來看看WebHost方式和SelfHost方式。
該Demo中包含一個類庫項目、一個控制台項目以及一個空的WebForm項目。其中類庫項目有一個繼承自ApiController的名為HomeController的類;控制台項目實現SelfHost;WebForm項目實現WebHost:
WebAPI代碼:
public class HomeController : ApiController { public string Get(string fromStr) { return $"The request is from {fromStr}"; } }
WebHost寄宿方式:
WebHost項目的Global文件代碼:
public class Global : System.Web.HttpApplication { protected void Application_Start(object sender, EventArgs e) { GlobalConfiguration.Configuration.Routes.MapHttpRoute(name: "default", routeTemplate: "api/{controller}/{fromStr}"); } }
啟動運行WebHost項目,瀏覽器輸入地址http://localhost:34827/api/home/webhost:
SelfHost寄宿方式:
SelfHost項目中的Program文件代碼:
static void Main(string[] args) { Assembly.Load("WebAPI,Version=1.0.0.1,Culture=neutral,PublicKeyToken=null"); HttpSelfHostConfiguration configuration = new HttpSelfHostConfiguration("http://localhost:34827/"); using (HttpSelfHostServer server = new HttpSelfHostServer(configuration)) { server.Configuration.Routes.MapHttpRoute(name: "default", routeTemplate: "api/{controller}/{fromStr}"); server.OpenAsync(); Console.Read(); } }
啟動運行SelfHost項目,瀏覽器輸入地址http://localhost:34827/api/home/from_selfhost:
從上面的例子可以看到Asp.Net WebAPI可以有多重寄宿方式,而Asp.Net WebAPI可以實現多種寄宿方式的原因在於:Asp.Net WebAPI有一個獨立於寄宿環境的抽象管道,這個抽象管道是Asp.Net WebAPI的消息處理管道。
下面正式進入今天的主題:Asp.Net WebAPI消息處理管道。Asp.Net WebAPI的消息處理管道是一組HttpMessageHandler的有序組合。在這個消息處理管道中,除了最后一個HttpMessageHandler外,其他的都是由DelegatingHandler這個類型組成的委托鏈,最后一個HttpMessageHandler是最終處理請求(查找Controller、執行Action)的地方。下面我們通過翻看源碼來看看組成消息處理管道的這個有序組合都是哪些類型:
在了解完組成Asp.NetWebAPI消息處理管道的類型后,我們通過一個例子來看看是怎么組成的。我們改一下前面的例子,在WebAPI項目中添加兩個自定義的HttpMessageHandler和自定義的HttpServer作為“龍頭”:
public class MyHttpMessageHanlder1 : DelegatingHandler { } public class MyHttpMessageHanlder2 : DelegatingHandler { } public class MyHttpServer:HttpServer { public MyHttpServer(HttpConfiguration configuration):base(configuration) { } public new void Initialize() { base.Initialize(); } }
修改HomeController的代碼:
public class HomeController : ApiController { public Tuple<IEnumerable<string>, IEnumerable<string>> Get(string fromStr) { HttpConfiguration configuration = new HttpConfiguration(); configuration.MessageHandlers.Add(new MyHttpMessageHanlder1()); configuration.MessageHandlers.Add(new MyHttpMessageHanlder1()); MyHttpServer server = new MyHttpServer(configuration); IEnumerable<string> handler1 = GetHandlers(server).ToArray(); server.Initialize(); IEnumerable<string> handler2 = GetHandlers(server).ToArray(); return new Tuple<IEnumerable<string>, IEnumerable<string>>(handler1, handler2); } private IEnumerable<string> GetHandlers(DelegatingHandler handler) { yield return handler.GetType().Name; while (handler.InnerHandler != null) { yield return handler.InnerHandler.GetType().Name; handler = handler.InnerHandler as DelegatingHandler; if (handler == null) break; } } }
運行程序后輸入地址http://localhost:34827/api/home/from:
由上面的例子,我們驗證了HttpServer為消息處理管道的“龍頭”,HttpRoutingDispatcher為管道的“龍尾”,我們自定義的委托鏈接點是保存在HttpConfiguration類型的MessageHanlers屬性中,在HttpServer調用Initialize方法時把MessageHandlers中的委托鏈節點和“龍頭”、“龍尾”組成一個消息處理管道委托鏈。
通過上面的實例我們知道了組成Asp.Net WebAPI消息處理管道的類型和驗證了Asp.Net WebAPI消息處理管道的創建,下面我們繼續看看作為消息處理管道的“龍頭”和“龍尾”內部都做了些什么。
當請求流轉到消息處理管道的最后一個節點時,通過源碼,如下,我們可以看到在最后的節點中完成的動作是:根據RouteData找到對應的Controller和Action,然后執行Action,將得到的響應數據逆序流轉到“龍頭”HttpServer中,在有HttpServer返回給客戶端。
總結:
通過前面的剖析,我們知道Asp.Net WebAPI有多種寄宿方式,是因為它有一個獨立於寄宿環境的消息處理管道,然后我們也對組成Asp.Net WebAPI消息處理管道的各種類型進行了剖析,並從中發現了消息處理管道是如何創建、請求是如何在管道中流轉以及各個管道的作用。
至此,我們對Asp.Net WebAPI消息處理管道進行了一個簡單的剖析,由於個人能力有限,如有不對,歡迎指正。