正如上篇文章所述那樣,OWIN在Web Server與Web Application之間定義了一套規(guī)范(Specs),意在解耦Web Server與Web Application,從而推進跨平臺的實現(xiàn)。若要真正使用OWIN規(guī)范,那么必須要對他們進行實現(xiàn)。目前有兩個產(chǎn)品實現(xiàn)了OWIN規(guī)范——由微軟主導(dǎo)的Katana和第三方的Nowin。這篇文章,我主要關(guān)注還是Katana,由微軟團隊主導(dǎo),開源到CodePlex上??梢栽?/span>Visual Studio中輸入命令:git clone https://git01.codeplex.com/katanaproject來查看源代碼。
在介紹Katana之前,我覺得有必要為大家梳理一下過去10幾年前ASP.NET 發(fā)展歷程。
ASP.NET Web Form 在2002正式發(fā)布時,面向的開發(fā)者主要有兩類:
為了迎合這兩類開發(fā)者,ASP.NET Web Form通過使用沉重的ViewState來保存頁面回傳過程中的狀態(tài)值,因為HTTP協(xié)議是無狀態(tài)的,通過ViewState,使原本沒有記憶的Http協(xié)議變得有記憶起來。這在當時是非常好的設(shè)計,能通過拖拽控件的形式快速開發(fā)Web,而不必過多的去關(guān)注底層原理。同時ASP.NET團隊還為ASP.NET豐富了更多的功能、諸如:Session、Cache、Configuration等等。
這在當時無疑是成功的,ASP.NET的發(fā)布迅速拉攏了開發(fā)者,在Web開發(fā)中形成了一股新的勢力,但同時也買下來一些隱患:
由于Web Form產(chǎn)生一大堆ViewState和客戶端腳本,這對開發(fā)者來說慢慢變成一種累贅,因為我們只想產(chǎn)生純凈的HTML標記。所以開發(fā)者更想去主動控制而非被動產(chǎn)生額外HTML標記。
所以微軟基于MVC設(shè)計模式推出了其重要的Web Framework——ASP.NET MVC Framework,通過Model-View-Control解耦了業(yè)務(wù)邏輯和表現(xiàn)邏輯,同時沒有了服務(wù)器端控件,將頁面的控制權(quán)完全交給了開發(fā)者。
為了快速更新迭代,通過Nuget來獲取更新,故從.NET Framework中分離開了。
但唯一不足的是,ASP.NET MVC還是基于ASP.NET Framework(注:ASP.NET MVC 6已經(jīng)不依賴System.Web),所以Web Application和Web Server依舊沒有解耦。
隨著時間的推移,一些問題開始暴露出來了,由于Web Server和Web Application緊耦合在一起,微軟在開發(fā)獨立、簡單的Framework上越發(fā)捉襟見肘,這和其他平臺下開源社區(qū)蓬勃發(fā)展形成鮮明對比,幸運的是,微軟做出了改變,推出了獨立的Web Framework ——ASP.NET Web API,他適用于移動互聯(lián)網(wǎng)并可以快速通過Nuget安裝,更為重要的是,他不依賴System.Web,也不依賴IIS,你可以Self-Host或者在其他Web Server部署。
隨著Web API能夠運行在自己的輕量級的宿主中,并且越來越多簡單、模塊化、專一的Framework問世,開發(fā)人員有時候不得不啟動單獨的進程來處理Web應(yīng)用程序的各種組件(模塊)、如靜態(tài)文件、動態(tài)文件、Web API和Socket。為了避免進程擴散,所有的進程必須啟動、停止并且獨立進行管理。這時,我們需要一個公共的宿主進程來管理這些模塊。
這就是OWIN誕生的原因,解耦成最小粒度的組件,然后這些標準化框架和組件可以很容易地插入到OWIN Pipeline中,從而對組件進行統(tǒng)一管理。而Katana正是OWIN的實現(xiàn),為我們提供了豐富的Host和Server。
Katana作為OWIN的規(guī)范實現(xiàn),除了實現(xiàn)Host和Server之外,還提供了一系列的API幫助開發(fā)應(yīng)用程序,其中已經(jīng)包括一些功能組件如身份驗證(Authentication)、診斷(Diagnostics)、靜態(tài)文件處理(Static Files)、ASP.NET Web API和SignalR的綁定等。
Katana實現(xiàn)了OWIN的Layers,所以Katana的體系結(jié)構(gòu)和OWIN一致,如下所示:
1.)Host :宿主Host被OWIN規(guī)范定義在第一層(最底層),他的職責(zé)是管理底層的進程(啟動、關(guān)閉)、初始化OWIN Pipeline、選擇Server運行等。
Katana為我們提供了3中選擇:
2.)Server
Host之后的Layer被稱為Server,他負責(zé)打開套接字并監(jiān)聽Http請求,一旦請求到達,根據(jù)Http請求來構(gòu)建符合OWIN規(guī)范的Environment Dictionary(環(huán)境字典)并將它發(fā)送到Pipeline中交由Middleware處理。Katana對OWIN Server的實現(xiàn)分為如下幾類:
3)Middleware
Middleware(中間件)位于Host、Server之后,用來處理Pipeline中的請求,Middleware可以理解為實現(xiàn)了OWIN應(yīng)用程序委托AppFun的組件。
Middleware處理請求之后并可以交由下一個Pipeline中的Middleware組件處理,即鏈式處理請求,通過環(huán)境字典可以獲取到所有的Http請求數(shù)據(jù)和自定義數(shù)據(jù)。Middleware可以是簡單的Log組件,亦可以為復(fù)雜的大型Web Framework,諸如:ASP.NET Web API、Nancy、SignlR等,如下圖所示:Pipeline中的Middleware用來處理請求:
4.)Application
最后一層即為Application,是具體的代碼實現(xiàn),比如ASP.NET Web API、SignalR具體代碼的實現(xiàn)。
現(xiàn)在,我想你應(yīng)該了解了什么事Katana以及Katana的基本原則和體系結(jié)構(gòu),那么現(xiàn)在就是具體應(yīng)用到實際當中去了。
在Startup的Configuration方法中實現(xiàn)OWIN Pipeline處理邏輯,如下代碼所示:
app.Run方法將一個接受IOwinContext對象最為輸入?yún)?shù)并返回Task的Lambda表達式作為OWIN Pipeline的最后處理步驟,IOwinContext強類型對象是對Environment Dictionary的封裝,然后異步輸出"Hello World"字符串。
細心的你可能觀察到,在Nuget安裝Microsoft.Owin.Host.SystemWeb程序集時,默認安裝了依賴項Microsoft.Owin程序集,正式它為我們提供了擴展方法Run和IOwinContext接口,當然我們也可以使用最原始的方式來輸出"Hello World"字符串,即Owin程序集為我們提供的最原始方式,這僅僅是學(xué)習(xí)上參考,雖然我們不會在正式場景下使用:
使用自定義Host托管Katana應(yīng)用程序與使用IIS托管差別不大,你可以使用控制臺、WinForm、WPF等實現(xiàn)托管,但要記住,這會失去IIS帶有的一些功能(SSL、Event Log、Diagnostics、Management…),當然這可以自己來實現(xiàn)。
使用自定義的Host將失去IIS的一些功能,當然我們可以自己去實現(xiàn)。幸運的是,Katana為我們默認實現(xiàn)了部分功能,比如Diagnostic,包含在程序集Microsoft.Owin.Diagnostic中。
在上述代碼中,當請求的路徑(Request.Path)為根目錄時,渲染輸出Webcome Page并且不繼續(xù)執(zhí)行Pipeline中的其余Middleware組件,如下所示:
如果請求的路徑為Error時,拋出異常,顯示錯誤頁,如下所示:
當然我們還可以使用Katana提供的OwinHost.exe來托管應(yīng)用程序,毫無疑問,通過Nuget來安裝OwinHost。
如果你按照我的例子一步一步執(zhí)行的話,你會發(fā)現(xiàn)不管使用ASP.NET/IIS托管還是自托管,Startup配置類都是不變的,改變的僅僅是托管方式。同理OwinHost也是一樣的,但它更靈活,我們可以使用類庫或者Web應(yīng)用程序來作為Application。
類庫作為Application,可以最小的去引用程序集,創(chuàng)建一個類庫后,刪除默認的Class1.cs,然后并且添加Startup啟動項,這會默認像類庫中添加Owin和Microsoft.Owin程序集的引用。
然后,使用Nuget來安裝OwinHost.exe,如Install-Package OwinHost,注意它并不是一個程序集,而是.exe應(yīng)用程序位于<solution root>/packages/OwinHost.(version)/tools文件夾。
因為類庫不能直接運行,那么只能在它的根目錄調(diào)用OwinHost.exe來托管,它將加載.\bin文件下所有的程序集,所以需要改變類庫的默認輸出,如下所示:
然后編譯解決方案,打開cmd,鍵入如下命令:
如上圖成功啟動了宿主Host并且默認監(jiān)聽5000端口。
OwinHost.exe還提供自定義參數(shù),通過追加-h來查看,如下所示:
既然類庫不能直接運行,當然你也不能直接進行調(diào)試,我們可以附加OwinHost進程來進行調(diào)試,如下所示:
注:
我在使用OwinHost.exe 3.0.1時,Startup如果是如下情況下,它提示轉(zhuǎn)換失敗,不知是否是該版本的Bug。
報錯信息如下:
Web Application比類庫使用起來輕松多了,你可以直接運行和調(diào)試,唯一比較弱的可能是它引用較多的程序集,你完全可以刪掉,比如System.Web。
通過Nuget安裝了OwinHost.exe之后,可以在Web中使用它,如下所示:
花了好久才最終完成這篇博客,為大家講解了Katana的世界,那么接下來我將繼續(xù)OWIN & Katana之旅,探索Middleware的創(chuàng)建,謝謝大家支持。