對於開發人員來說,代碼就是最好的文檔,如上一篇博文所說,下面我們就會基於Kanata項目的一些具體調用代碼,來進一步深入理解OWIN的實現和作用.
今天我們先針對Host和Server來實現一個簡單的應用.
我們的開發環境是: VS2013 Update 3, .Net Framework 4.5.1
Host開發
如上篇博文提及,Host具有如下特點:
- 實現一個宿主進程
- 負責Server的啟動和關閉
- 負責Middleware和Application的裝載
最簡單的宿主進程就是Console Application,那么我們從建立Console程序開始

注意這個程序和它的入口類(一般是Program.cs)就是我們所說的Host宿主進程的實現.
而具體的Host和Server的實現我們就需要借助Kanata項目的實現了.
首先通過Nuget獲取Kanata的Host實現. 包名為: Microsoft.Owin.Hosting

注: 目前版本為3.0.1, Owin的2個核心組件: Owin和Microsoft.Owin會被同時載入.
WebApp.Start
Host的主要用途是啟動和關閉Server, 這個功能的實現類就是在Microsoft.Owin.Hosting下的WebApp類, 請看類結構:

我們可以看到,WebApp只有若干個Start函數,輔助於StartOptions類,依靠這2個類,就能完成Host對Server的啟動和關閉.
Start函數有好幾個重載,我們來看一個最為典型的實現. (其他實現大同小異,如果要使用請參閱相關文檔)
public static System.IDisposable Start(Microsoft.Owin.Hosting.StartOptions options, System.Action<IAppBuilder> startup)
- Options參數定義了Server啟動所需的參數.
- Startup參數是一個以Owin.IAppbuilder接口為參數的函數,通過這個函數,完成對Server所需Middleware的加載工作,這也是Host的關鍵作用之一!
- 函數返回一個實現IDisposable接口的類, 可以預見的是,當這個類Dispose的時候,被這個函數啟動的Server也會同時關閉和消亡.
StartOptions
我們先來看下這個StartOptions中2個比較關鍵的屬性:
public System.Collections.Generic.IList<string> Urls { get; }
Urls參數是以http標准url為格式字符串來定義Server監聽的HostName和Port.
標准格式是 http(s)://hostname:port ; 比如 http://localhost:8080 ; https://192.168.1.1:9000;
注意,Urls可以加多個,表示支持不同的hostname和port映射. 另外, 還支持http://*:9000 這樣的格式,表示映射所有HostName,這個和IIS映射配置其實是類似的.
public string ServerFactory { set; get; }
關鍵的來了,這個就是Server實現類的assembly name, 大家不難想到,通過這個屬性,Host和Server是完全解耦的. 我們的這個Host可以和任何符合Owin接口的Server實現進行組合. 當然,目前還是使用自家的Server實現,請看下節.
Server實現和引用
Http Server並不是一兩句代碼可以實現的, 這里我們還是繼續站在Kanata的肩膀上,借用它的Server實現. 他的Server實現包名為 : Microsoft.Owin.Host.HttpListener (我認為這里的Host改名為Server更加貼切)
首先還是使用Nuget獲取該Server組件

安裝,並引入項目,有了Server的實現,下面我們來完成StartOptions的定義代碼:
//初始化StartOptions參數 StartOptions options = new StartOptions(); //服務器Url設置 options.Urls.Add("http://localhost:9000"); options.Urls.Add("http://192.168.1.1:8080"); //Server實現類庫設置 options.ServerFactory = "Microsoft.Owin.Host.HttpListener";
需要注意的是,我這里特地放了2個port不同的地址,這2個Url都能起到效果; 另外Microsoft.Owin.Host.HttpListener 其實是默認的Host ServerFatory實現(最后一行代碼可以省略); 但我們必須理解,這里是可以解耦的,我們完全可以橋接其他的Server實現.
Startup函數和使用
Startup函數非常的簡單,就是一個只有一個沒有返回值的,只有一個Owin.IAppBuilder參數的函數(函數名任意,不一定要叫Startup). 如以下代碼:
private static void Startup(Owin.IAppBuilder app) { //這里通過app句柄,為當前Server加入所有需要的middleware }
在這個函數中,通過app參數提供的句柄,一步步的加入Server所需要的所有Middleware,當然這些Middleware都是可自由組合,自由拆卸的,非常的靈活.
Server的啟動和關閉
有了Options和Startup函數,我們就可以啟動我們的Server了,整合的代碼如下:
/// <summary> /// Owin Host 主進程入口函數 /// </summary> static void Main() { //初始化StartOptions參數 StartOptions options = new StartOptions(); //服務器Url設置 options.Urls.Add("http://localhost:9000"); options.Urls.Add("http://192.168.1.1:8080"); //Server實現類庫設置 options.ServerFactory = "Microsoft.Owin.Host.HttpListener";
//以當前的Options和Startup啟動Server using (WebApp.Start(options, Startup)) { //顯示啟動信息,通過ReadLine駐留當前進程 Console.WriteLine("Owin Host/Server started,press enter to exit it..."); Console.ReadLine(); }//Server在Dispose中關閉 } private static void Startup(Owin.IAppBuilder app) { //這里通過app句柄,為當前Server加入所有需要的middleware }
Server的關閉很簡單,當using的結尾觸發Dispose時,該Server被自動關閉.
Server是獨立線程運行的,所以宿主進程必須駐留,這里用Console.ReadLine()駐留當前線程,保證Server長期運行.
其他注意點
- 很多機器上出現權限不夠情況,請用管理員賬號運行VS2013.
- 用瀏覽器訪問2個地址時發現可以聯通,但Reponse為空,這符合上一篇中說提到的: Server僅僅是一個空的實現,在沒有任何Middleware裝載的情況下(我們的Startup函數為空),所有的Request都只能獲得一個空的Response這一論點.
- 加入不同的Middleware能夠實現不同的Reponse返回,這個將在以后的篇幅中繼續討論.
- 盡量用Nuget獲取我們需要的組件包,以保證組件正確性和版本統一.
總結下,我們開發了一個以Console Application為宿主進程的程序,通過Kanata的Host實現Microsoft.Owin.Hosting啟動了它自身的Server實現 Microsoft.Owin.Host.HttpListener, 目前沒有加入任何Middleware和Application實現.
這里再羅嗦一句, Kanata的Host和Server實現完全可以被自己或者第三方的實現所取代,前提是,符合OWIN的標准.
