上一回合中,我們講解了Linux.NET面對(duì)OWIN需要做出的準(zhǔn)備,以及介紹了如何將兩個(gè)支持OWIN協(xié)議的框架:SignalR以及NancyFX以O(shè)winHost的方式部署到Linux.NET當(dāng)中。這一章,我們將對(duì)框架與OwinHost之間怎么通過(guò)OWIN協(xié)議作出解析。
本章我們將討論學(xué)習(xí):
(1)、連接兩世界之門(mén)——“Middleware“
(2)、轉(zhuǎn)動(dòng)大門(mén)的鑰匙,打開(kāi)無(wú)盡的財(cái)寶
(3)、適配器?轉(zhuǎn)換插頭
相關(guān)示例代碼,可以點(diǎn)擊這里進(jìn)行下載。
1、充當(dāng)”門(mén)“的”Middleware“
英文名”Middleware“,中文名”中間件“,要了解什么是Middleware,我們先看看OWIN協(xié)議中的分層。

上圖為OWIN分層的一個(gè)簡(jiǎn)圖。最下的一層是我們的操作系統(tǒng),Linux、Windows、Unix、Mac或其他;對(duì)上一層則是運(yùn)行于操作系統(tǒng)中的OwinHost;再往上一層也就是紫色那層是基于OWIN協(xié)議建立的基礎(chǔ)框架;而最頂層則是我們基于這些OWIN協(xié)議的框架所誕生的應(yīng)用程序(直接操作OWIN字典的暫不記錄在圖中)。
拋開(kāi)最頂和最底兩層不管,當(dāng)用戶從客戶端發(fā)起一請(qǐng)求,經(jīng)過(guò)漫長(zhǎng)的網(wǎng)絡(luò),到達(dá)目標(biāo)主機(jī)時(shí),請(qǐng)求將被并且僅能被OwinHost捕獲,因?yàn)橹挥蠴winHost在持續(xù)的不斷監(jiān)聽(tīng)端口。雖然請(qǐng)求已經(jīng)被OwinHost捕獲,但是OwinHost并沒(méi)有能力對(duì)這個(gè)剛捕獲的請(qǐng)求做出處理(這里特指需要經(jīng)過(guò)OWIN框架及相關(guān)應(yīng)用程序處理的請(qǐng)求)即使它知道自身有請(qǐng)求需要處理。
同樣的,我們?cè)侔涯抗廪D(zhuǎn)到OWIN框架,它是我們的”處理中樞“,它能夠?qū)ξ覀儼盐覀兊妮斎胪ㄟ^(guò)適當(dāng)?shù)挠?jì)算之后把正確的答案輸出來(lái),但是它也有一個(gè)缺點(diǎn),那就是它自身沒(méi)有辦法收集”相關(guān)信息“,也就是它自己并不能產(chǎn)生出”輸入“。
這就好比人的大腦與其他器官,OWIN框架是我們的”大腦“,OwinHost則是我們的”器官“,沒(méi)有了大腦我們的其他器官也無(wú)法正常運(yùn)行(當(dāng)然咯,有點(diǎn)功能不需要大腦,就像有些OwinHost處理靜態(tài)資源不需要經(jīng)過(guò)OWIN框架一樣),沒(méi)有了其他“器官”的支持“大腦”也無(wú)法發(fā)揮作用甚至?xí)劳觯](méi)有宿主,OWIN框架也無(wú)法運(yùn)行)。

因此,我們需要有相應(yīng)的“神經(jīng)”來(lái)連通我們的“器官”與“大腦”之間的通信。而Middleware發(fā)揮的就是這種作用,它是連接OwinHost與OWIN框架的門(mén),OwinHost把捕獲到的請(qǐng)求通過(guò)自身的處理后通過(guò)這扇門(mén)推送到OWIN框架中;而OWIN框架也自己對(duì)請(qǐng)求計(jì)算后得出的響應(yīng)通過(guò)這扇門(mén)返回到OwinHost中,再由OwinHost推送到用戶手上。
而事實(shí)上,Middleware作為一扇連接OwinHost與OWIN框架的門(mén),讓這兩個(gè)世界得以交流以外,還發(fā)揮著另外一個(gè)作用,那就是規(guī)定了統(tǒng)一的信息出入口,所有的請(qǐng)求響應(yīng)均只能夠通過(guò)這扇門(mén)傳遞,這或者可以更方便的對(duì)一些敏感信息、惡意代碼之流的數(shù)據(jù)進(jìn)行攔截與過(guò)濾。
2、轉(zhuǎn)動(dòng)我們手中的鑰匙
正如上一節(jié)中最后所講到的一樣,Middleware作為OWIN框架與OwinHost的唯一通道,這意味著無(wú)論是SignalR、NancyFX、Webapi、FubuMVC或是其他,它們所站立的起點(diǎn)高度都是一致的,我們只要把能握住Middleware,就相當(dāng)于把握住了大門(mén)的鑰匙,我們也可以做出我們自己的框架出來(lái)。這也是我在上一回合中所提到OWIN協(xié)議給我們帶來(lái)的好處中的第二點(diǎn):“它給鼓勵(lì)了一批人把自己的想法變成現(xiàn)實(shí)”。
本節(jié)我們將簡(jiǎn)述如何直接操作OWIN字典,直接和OwinHost進(jìn)行通信。
首先我們需要在Visual Studio中建立我們的項(xiàng)目,然后通過(guò)NuGet獲得OWIN:

然后我們新建一個(gè)類(lèi),并以它作為我們的Middleware:

using System;using System.Collections.Generic;using System.IO;using System.Text;using System.Threading.Tasks;namespace Demo1{ using AppFun = Func<IDictionary<string, object>, Task>; public class MyMiddleware { PRivate readonly AppFun _env; public MyMiddleware(AppFun env) { if (env == null) throw new ArgumentNullException("OWIN環(huán)境參數(shù)為空"); this._env = env; } public Task Invoke(IDictionary<string, object> env) { var responseBody = "Linux.NET 學(xué)習(xí)手記(8) --小蝶驚鴻"; var responseBodyBytes = Encoding.UTF8.GetBytes(responseBody); ((IDictionary<string, string[]>)env["owin.ResponseHeaders"]).Add("Content-Type", new string[] { "text/html; charset=utf-8" }); ((Stream)env["owin.ResponseBody"]).Write(responseBodyBytes, 0, responseBodyBytes.Length); return this._env(env); } }}MyMiddleware這里要對(duì)代碼進(jìn)行一番的解析: (1)、這是我們的Middleware,所有來(lái)自于OwinHost的請(qǐng)求數(shù)據(jù)以及OWIN框架響應(yīng)的數(shù)據(jù)都要通過(guò)這個(gè)類(lèi)來(lái)進(jìn)行統(tǒng)一中轉(zhuǎn)處理。
(2)、IDictionary<string, object>實(shí)則為OWIN字典,里面包含了基于OWIN協(xié)議的用于OwinHost與OWIN框架之間通信的數(shù)據(jù)信息。
(3)、程序啟動(dòng)時(shí),OwinHost會(huì)先實(shí)例化這個(gè)類(lèi)(實(shí)則調(diào)用Startup中的Configuration,然后實(shí)例化這個(gè)類(lèi),稍后我們會(huì)對(duì)此進(jìn)行講述),繼而執(zhí)行這個(gè)類(lèi)的構(gòu)造函數(shù)對(duì)Environment(也就是那個(gè)env)進(jìn)行初始化。
(4)、每次OwinHost捕獲到請(qǐng)求之后,會(huì)調(diào)用Invoke,OWIN字典會(huì)攜帶請(qǐng)求進(jìn)入該方法,程序處理完成之后,OWIN字典則會(huì)攜帶OWIN框架的響應(yīng)離開(kāi)該方法。
創(chuàng)建好我們的Middleware之后,我們需要在項(xiàng)目的根目錄新建一個(gè)名為“Startup”的類(lèi),并在此類(lèi)里面創(chuàng)建一個(gè)名為“Configuration”的方法。

namespace Demo1{ using Owin; public class Startup { public void Configuration(IAppBuilder app) { app.Use(typeof(MyMiddleware)); } }}Startup.cs這里也要為這個(gè)類(lèi)作出一番解析:OwinHost嘗試驅(qū)動(dòng)OWIN框架時(shí),它會(huì)嘗試尋找Startup,并激活里面的Configuration,繼而激活我們自定義的Middleware。OwinHost激活我們的Middleware之后,OwinHost與OWIN框架之間就建立了連接,連接這兩個(gè)世界的“門(mén)”也就打開(kāi)了。
在示例代碼中,Demo1為講解如何通過(guò)簡(jiǎn)單的操作OWIN字典獲取并返回我們想要輸出的結(jié)果。

Demo2則是模擬asp.net MVC的路由功能,OwinHost激活Startup時(shí),程序會(huì)對(duì)自身的程序集進(jìn)行反射,找出所有以“Controller”結(jié)尾的類(lèi),并把里面的方法注冊(cè)到路由字典中。當(dāng)有來(lái)自于用戶的請(qǐng)求,程序則會(huì)自動(dòng)的拆解URL并在路由字典中判斷是否存在改頁(yè)面,存在則繼而激活相應(yīng)的方法(Action),不存在則導(dǎo)向到404頁(yè)面。其效果如下圖所示:

成功的路由導(dǎo)向到Home/Index 頁(yè)面

訪問(wèn)一個(gè)不存在的地址,路由導(dǎo)向到一個(gè)404的小動(dòng)畫(huà)。
事實(shí)上,由于我們是基于OWIN協(xié)議直接操作OWIN字典所誕生的小Demo,因此我們是可以以一種無(wú)障礙的方式直接將項(xiàng)目發(fā)布到Linux.NET中運(yùn)行。
3、充當(dāng)轉(zhuǎn)換插頭角色的適配器
可能有細(xì)心而又愛(ài)動(dòng)腦筋的讀者不禁問(wèn)到,關(guān)于那兩個(gè)Demo(也能泛指其他所有的OWIN框架),OwinHost已經(jīng)有了(Katana或者Jexus或其他),Middleware也由我們自行提供,不是OwinHost就可以與OWIN框架之間作出通信了嗎?上一回合中所出現(xiàn)的適配器又是怎么回事?為什么沒(méi)有見(jiàn)到Windows版的適配器?
在解析這個(gè)之前,我先上一張能夠很恰當(dāng)比喻適配器的圖片:

這是我隨手從網(wǎng)上找來(lái)的圖片,用過(guò)它的讀者很容易就能夠分辨出來(lái)它是一個(gè)轉(zhuǎn)換插頭,它能夠把各種類(lèi)型的原插口轉(zhuǎn)換成通用的插口。對(duì)的,沒(méi)錯(cuò),如果以簡(jiǎn)單的方式來(lái)理解,適配器所起的所用正式OwinHost與OWIN框架之間的轉(zhuǎn)換插頭,它把OwinHost中所提供的原始數(shù)據(jù)格式化成OWIN字典供OWIN框架使用。這就是簡(jiǎn)單的理解方式。
更深入的方式來(lái)理解,適配器發(fā)揮著兩個(gè)重要的作用,除了簡(jiǎn)單理解中所講述的作用以外,它還充當(dāng)著讓OwinHost成功驅(qū)動(dòng)Startup并激活Configuration的關(guān)鍵。有興趣的讀者可以打開(kāi)Jexus針對(duì)于OWIN框架的適配器,你會(huì)發(fā)現(xiàn)原來(lái)它也是通過(guò)反射尋找Startup類(lèi)并激活里面的Configuration來(lái)創(chuàng)建Middleware并建立連接的,了解了這一點(diǎn)之后,我們可以通過(guò)修改適配器的源碼來(lái)更改OwinHost嘗試驅(qū)動(dòng)OWIN框架時(shí)最先激活的類(lèi),我們可以根據(jù)自己的愛(ài)好把“Startup”這個(gè)名字改為“Breakdown”、“Sunday”或者“ILoveChina”甚至“ILoveXiaodiejinghong”,也可以把“Configuration”改為其他……總之你喜歡的。
至于為何Katana沒(méi)有適配器,我這里只能說(shuō):“可能已經(jīng)內(nèi)置了吧”(具體還需要各位讀者查看源碼,我沒(méi)有查看過(guò),因此沒(méi)有發(fā)言權(quán))。
好的,兩回合文章我們簡(jiǎn)單的認(rèn)知了一些關(guān)于OWIN的事情,OWIN作為微軟提出一套重要協(xié)議具有重大的戰(zhàn)略意義。不多說(shuō)了,我們下回再見(jiàn)吧。謝謝。
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注