ASP.NET MVC項(xiàng)目部署與IIS版本變化介紹
asp.net mvc 1.0正式發(fā)布至今已將近四個(gè)月了,想必了解asp.net mvc的人越來(lái)越多。打算寫一點(diǎn)關(guān)于如何部署asp.net mvc的文字。
內(nèi)容包括:IIS的版本變化,asp.net的工作原理等。
涉及的東西比較基礎(chǔ),內(nèi)容也比較多,肯定會(huì)有我們已經(jīng)知道的東西,但是為了完整性,可能會(huì)分(一)、(二)……如果你對(duì)asp.net不太熟悉的話,可能閱讀中會(huì)遇到一些理解不了的地方,在這些地方我會(huì)給出推薦您閱讀的書籍或者園友的文章供你參考,如果你是asp.net高級(jí)開(kāi)發(fā)人員的話可以略過(guò)。
主要參考資料:Pro asp.net mvc Framework.pdf(你可以搜索下載到)
部署,就是將你的網(wǎng)站發(fā)布到服務(wù)器上以使人們可以實(shí)際使用。如果你曾經(jīng)部署過(guò)asp.net項(xiàng)目的話,你將會(huì)發(fā)現(xiàn)部署asp.net mvc實(shí)際上跟部署 asp.net差不多,唯一特殊的地方是asp.net mvc使用到了Routing,可能有人嘗試過(guò)在IIS6上使用無(wú)后綴URL的方法,如果你知道了下面這些列出的內(nèi)容的話,就會(huì)變得很容易了。
asp.net mvc宿主服務(wù)器所需的條件。
IIS處理請(qǐng)求的架構(gòu),路由是如何與之融為一體的。
安裝IIS6和7到Windows服務(wù)器,將asp.net mvc項(xiàng)目部署在他們上。
配置你的asp.net mvc項(xiàng)目。
該篇包含前兩個(gè)內(nèi)容
ASP.NET MVC項(xiàng)目部署之服務(wù)器環(huán)境
要運(yùn)行asp.net mvc項(xiàng)目,我們的服務(wù)器需要滿足如下條件:
IIS5.1或者更高版本的IIS,并且開(kāi)啟了asp.net服務(wù)。
.NET Framework 3.5(***同時(shí)安裝了SP1)
推薦的操作系統(tǒng)是Windows server 2003(IIS6)和Windows server 2008(IIS7)。asp.net mvc本身不要求服務(wù)器必須安裝了它。因?yàn)槲覀儗ystem.Web.mvc.dll和你或許用到的Microsoft.Web.mvc.dll直接放在\Bin文件夾中部署就可以了,這種部署方式叫做私有部署,如果你買的空間沒(méi)有安裝asp.net mvc的話(即GAC中沒(méi)有上述的兩個(gè)dll)通過(guò)私有部署的方式也很容易,另外如果你的服務(wù)器沒(méi)有安裝過(guò).NET Framework SP1的話,你還需要將System.Web.Abstractions.dll和System.Web.Routing.dll也拷貝到你的\Bin文件夾中。下面會(huì)詳述這些。
asp.net mvc對(duì)我們買的虛擬服務(wù)器有什么樣的要求
除了需要服務(wù)器支持asp.net 2.0和安裝了.NET Frameworkd 3.5之外沒(méi)有其他要求。所以我們看不到有空間提供商打廣告說(shuō)自己的空間支持asp.net mvc,因?yàn)橥ㄟ^(guò)把相關(guān)的程序集放在\Bin文件夾中你同樣可以私有部署你的asp.net mvc項(xiàng)目。
如果你的服務(wù)器提供商用的是IIS7,那么IIS7與asp.net的集成管線模式可以給你帶來(lái)干凈的無(wú)后綴的URL,如果是IIS6的話雖然也能夠做到,但是就沒(méi)有IIS7那么高效、方便和容易了,下文會(huì)有關(guān)于Windows server 2003/IIS6的內(nèi)容。
關(guān)于IIS版本變化
IIS6/ Windows Server 2003。
IIS7/Windows Server 2008。
IIS 7.5/Windows Server 2008 R2(尚未發(fā)布)。
我們僅僅介紹6.0之后版本的IIS,下面我們來(lái)快速覆蓋一下IIS的知識(shí),包括:虛擬路徑、綁定設(shè)置和應(yīng)用程序池。***談一下IIS內(nèi)部是如何處理請(qǐng)求的(IIS7是如何處理無(wú)后綴的URL的)。
理解網(wǎng)站和虛擬目錄
IIS可以同時(shí)宿主多個(gè)不同的網(wǎng)站,我們對(duì)每一個(gè)網(wǎng)站指定一個(gè)根目錄,這個(gè)目錄可以是服務(wù)器的本機(jī)目錄也可以在網(wǎng)絡(luò)的其他地方,然后IIS就可以從它所管理的那些目錄下尋找或獲得相應(yīng)靜態(tài)或動(dòng)態(tài)請(qǐng)求的內(nèi)容給我們了。
為了指導(dǎo)特定的HTTP請(qǐng)求到相應(yīng)的相應(yīng)網(wǎng)站,IIS允許我們配置“綁定”。所謂“綁定”就是將一個(gè)特定的IP、TCP端口號(hào)、和HTTP主機(jī)名對(duì)應(yīng)到特定的網(wǎng)站。如下圖:
作為一個(gè)額外的配置,你還可以在網(wǎng)站目錄文件夾任意層級(jí)上添加虛擬目錄,每一個(gè)虛擬目錄表示IIS將從其他地方提取或獲得內(nèi)容返回給對(duì)該虛擬目錄的請(qǐng)求,這取決于你建立的虛擬目錄所指定的文件夾的位置(它同樣可以在本機(jī)也可以在網(wǎng)絡(luò)的其他地方)。虛擬目錄的目的是讓真實(shí)文件所在的位置與網(wǎng)站目錄列表脫離關(guān)系,有點(diǎn)類似文件夾的“快捷方式”,虛擬目錄的存在使得外界不知道我們的真實(shí)文件所在具體位置,個(gè)人感覺(jué)邏輯上的意義大于安全上的意義。
說(shuō)明:IIS7/IIS7.5中虛擬目錄的顯示
對(duì)于每一個(gè)虛擬目錄你還可以選擇是否賦予它獨(dú)立的應(yīng)用程序地位。如果選擇這樣做,該虛擬目錄對(duì)應(yīng)的獨(dú)立的應(yīng)用程序就擁有自己獨(dú)立的配置文件了,如果該獨(dú)立的應(yīng)用程序是個(gè)asp.net應(yīng)用程序的話,那么它的狀態(tài)也是獨(dú)立的啦,是與它的父級(jí)應(yīng)用程序的狀態(tài)無(wú)關(guān)的。顯然,因?yàn)樗麄兪窍嗷オ?dú)立的應(yīng)用程序,所以被設(shè)置成獨(dú)立的應(yīng)用程序的這個(gè)虛擬目錄中所運(yùn)行的asp.net完全可以是和父級(jí)不同的版本的asp.net。
從IIS6開(kāi)始,IIS引入了應(yīng)用程序池(application pools)。應(yīng)用程序池用來(lái)隔離同一臺(tái)服務(wù)器上的多個(gè)同時(shí)運(yùn)行的應(yīng)用程序,每一個(gè)應(yīng)用程序池工作在一個(gè)獨(dú)立的工作進(jìn)程中,設(shè)定相應(yīng)的***內(nèi)存和CPU使用量,進(jìn)程回收時(shí)間表,等。每一個(gè)網(wǎng)站或設(shè)置為獨(dú)立應(yīng)用程序的虛擬目錄應(yīng)用程序都會(huì)被分配到建立起來(lái)的IIS的應(yīng)用程序池的其中一個(gè)池中去。一般的話,每個(gè)應(yīng)用程序應(yīng)建立一個(gè)應(yīng)用程序池而不是與其他應(yīng)用程序共用。這樣可以保證如果一個(gè)應(yīng)用程序崩潰了不影響其他應(yīng)用程序的正常運(yùn)行。參考:應(yīng)用程序池
綁定網(wǎng)站到主機(jī)名、IP地址和端口
因?yàn)橥粋€(gè)服務(wù)器可以宿主多個(gè)網(wǎng)站,所以就需要一個(gè)系統(tǒng)來(lái)分派請(qǐng)求到正確的Web應(yīng)用程序。上文提到,我們可以綁定網(wǎng)站到一個(gè)或者多個(gè):
端口號(hào)
主機(jī)名
IP地址(僅當(dāng)服務(wù)器有多個(gè)IP地址時(shí)——比如有多個(gè)網(wǎng)絡(luò)適配器)
對(duì)于主機(jī)名和IP地址,你可以選擇不做任何指定,不做任何指定等于是一個(gè)通配符,這樣的話對(duì)于所有不匹配特定網(wǎng)站的請(qǐng)求就會(huì)匹配給它。如果多個(gè)網(wǎng)站具有相同的綁定設(shè)置的話,同一時(shí)間只可能有一個(gè)是可用的,其它的處于停掉的狀態(tài),否則就不唯一了,對(duì)吧。虛擬目錄繼承父級(jí)應(yīng)用程序的綁定設(shè)置。
IIS是如何處理進(jìn)來(lái)的請(qǐng)求并調(diào)用asp.net的
當(dāng)IIS將接收到的一個(gè)請(qǐng)求分配給相應(yīng)的網(wǎng)站的時(shí)候,它需要決定怎么來(lái)處理這個(gè)請(qǐng)求。它是要直接從磁盤返回一個(gè)靜態(tài)內(nèi)容呢,還是要調(diào)用網(wǎng)站應(yīng)用程序執(zhí)行它并動(dòng)態(tài)地生成內(nèi)容來(lái)返回呢?它是如何決定這些的?
作為一個(gè)asp.net mvc程序域,你需要理解IIS的這個(gè)機(jī)制,不僅是asp.net mvc程序員,asp.net程序員都需要理解這個(gè)機(jī)制(asp.net程序員包含asp.net mvc程序員)——至少應(yīng)該有個(gè)基本了解;否則,你將會(huì)在理解進(jìn)來(lái)的請(qǐng)求與你的路由配置映射時(shí)遇到困難。
IIS版本變化:IIS6和IIS7在傳統(tǒng)模式下是如何處理請(qǐng)求的
如果你沒(méi)有使用IIS7的集成管線模式的話,你使用的將是回歸到IIS5的傳統(tǒng)管道模型。在這個(gè)模式下,IIS只能提供靜態(tài)內(nèi)容和具有特定擴(kuò)展名的從而可以映射到相應(yīng)的ISAPI的URL返回的動(dòng)態(tài)內(nèi)容。
IIS分析請(qǐng)求近來(lái)的URL,取得它的擴(kuò)展名(比如:http://hostname/folder/file.aspx?foo=bar的擴(kuò)展名是.aspx),將該擴(kuò)展名發(fā)往相應(yīng)的ISAPI擴(kuò)展程序。對(duì)于IIS6和IIS7來(lái)說(shuō),你都可以配置ISAPI擴(kuò)展程序與擴(kuò)展名的映射,對(duì)于IIS7來(lái)說(shuō),你還可以使用處理器映射配置工具(裝的不是中文版IIS翻譯不準(zhǔn),英文為Handler Mappings configuration tool),如下圖所示。
說(shuō)明:Windows7/IIS7.5
上圖中*.aspx被配置給了aspnet_isapi.dll,aspnent_isapi.dll這個(gè)非托管的dll在操作系統(tǒng)啟動(dòng)時(shí)就已經(jīng)被IIS加載到了內(nèi)存中,該dll與托管環(huán)境進(jìn)行交互然后將控制權(quán)轉(zhuǎn)交給該應(yīng)用程序所在的隔離的應(yīng)用程序域的.NET CLR,CLR接到控制權(quán)后,接著實(shí)例化一個(gè)HttpRuntime類對(duì)象,然后調(diào)用該HttpRuntime實(shí)例對(duì)象的ProcessRequest方法從而驅(qū)動(dòng)后續(xù)的處理,當(dāng)ProcessRequest執(zhí)行結(jié)束的時(shí)候封裝請(qǐng)求上下文信息的Datacontext實(shí)例就被構(gòu)建完成了,繼續(xù),進(jìn)入asp.net運(yùn)行時(shí)管道(可能叫做管線會(huì)更好些,MSDN上翻譯的是管線),這個(gè)管道就像是條工廠中車間的流水線,而這條流水線上加工的對(duì)象就是前面HttpRuntime實(shí)例化出來(lái)的那個(gè)封裝請(qǐng)求上下文信息的DataContext實(shí)例對(duì)象,每個(gè)HTTP模塊和管道后端的HTTP處理程序都是一道加工工序,這些工序有的負(fù)責(zé)驗(yàn)證權(quán)限,有的負(fù)責(zé)asp.net的狀態(tài)管理等,我把這個(gè)過(guò)程不確定的歸結(jié)為職責(zé)鏈模式(C:\Windows\Microsoft.NET\Framework\v2.0.50727\CONFIG路徑下< httpModules>節(jié)點(diǎn)中注冊(cè)了這些默認(rèn)的HTTP模塊),接下來(lái)就是在管道中按照HTTP模塊注冊(cè)的順序挨個(gè)執(zhí)行各個(gè)HTTP模塊,***到達(dá)管道尾端的HTTP處理程序,比如我們的Page類就是一個(gè)實(shí)現(xiàn)了IHttpHandler接口的處理程序。再往下就是控件以及頁(yè)面生命周期等這些我們非常熟悉的東西了。值得說(shuō)明的是,在我們的Global.asax中從System.Web.HttpApplication類繼承而來(lái)的那個(gè)自定義類中按照約定的方式書寫代碼就是我們與所有這些Http模塊們交互的方式了。其實(shí)對(duì)于System.Web.UI.Page的實(shí)例化實(shí)際上是通過(guò)工廠來(lái)返回的,上圖注冊(cè)*.aspx的時(shí)候就是注冊(cè)到了默認(rèn)的PageHandlerFactory工廠了,該工廠實(shí)例再根據(jù)前面所有那些步驟中一直存在的***封裝到了DataContext中的請(qǐng)求的URL對(duì)應(yīng)的文件名來(lái)查找相應(yīng)文件名的的真實(shí)的.aspx文件,并讀取該文件的***行指令,指令指定了最終負(fù)責(zé)處理該請(qǐng)求的HTTP處理程序類,這個(gè)類就是我們編寫的 System.Web.UI.Page類(一般是從Page繼承過(guò)來(lái)的子類)。接下來(lái)服務(wù)器控件與組件以及頁(yè)面的執(zhí)行最終生成HTML頁(yè)面內(nèi)容,生成的HTML結(jié)果返回給開(kāi)始的aspnet_isapi擴(kuò)展***被IIS輸出。而控件以及頁(yè)面生命周期等這些已經(jīng)是我們非常熟悉的領(lǐng)域了。有興趣的話你可以翻閱MSDN或者覺(jué)得有什么意義的話更進(jìn)一步用Reflector沿著流程從System.Web.UI.PageHandlerFactory開(kāi)始查看源代碼。
說(shuō)明:Http模塊就是實(shí)現(xiàn)了IHttpModule接口的類,Http處理程序就是實(shí)現(xiàn)了IHttpHandler接口的類。老趙說(shuō)過(guò):如果你不理解Http模塊和Http處理程序的話就不能稱為真正熟悉asp.net,之所以要理解HttpModule和HttpHandler是因?yàn)槔斫饬怂麄冎蟛拍苊髅靼装椎鼗贖ttpModule和HttpHandler進(jìn)行編程,擴(kuò)展我們的asp.net應(yīng)用程序管線中的內(nèi)容(原話可能不是這樣,意思應(yīng)該是這樣)。如果你想了解HttpModule和HttpHandler的話,有兩本書非常值得推薦:微軟出版社的《asp.net 3.5技術(shù)內(nèi)幕》和Wrox的《asp.net 2.0服務(wù)器控件與組件高級(jí)編程》這兩本書的相關(guān)章節(jié)都有對(duì)該主題較好的介紹。閱讀小洋(燕洋天工作室)的淺談asp.net內(nèi)部機(jī)制系列或者張子陽(yáng)的關(guān)于asp.net的文章也是一個(gè)不錯(cuò)的選擇。asp.net mvc在HttpModule和HttpHandler級(jí)別上與原來(lái)的asp.net是完全一樣的。
asp.net是如何被關(guān)聯(lián)的
在你安裝.NET Framework的時(shí)候(或者執(zhí)行aspnet_regiis.exe的時(shí)候),安裝程序自動(dòng)注冊(cè)了*.aspx,*.axd,*.ashx,和其他一些擴(kuò)展名到一個(gè)特殊的名字叫做aspnet_isapi.dll的ISAPI擴(kuò)展程序。一個(gè)請(qǐng)求必須與一個(gè)注冊(cè)過(guò)的擴(kuò)展名相匹配,然后IIS將激活aspnet_isapi.dll,這個(gè)非托管的dll再把控制權(quán)轉(zhuǎn)交給托管代碼,接下來(lái)就是托管代碼的時(shí)間了,.NET CLR在一個(gè)不同的進(jìn)程中執(zhí)行這些接下來(lái)的非托管代碼。
無(wú)后綴URL的問(wèn)題
傳統(tǒng)上,該系統(tǒng)對(duì)asp.net服務(wù)器頁(yè)面來(lái)說(shuō)一切正常,因?yàn)樗鼈儗?duì)應(yīng)真實(shí)的以.aspx為后綴文件真實(shí)的存在與磁盤上。但是,對(duì)于新的路由系統(tǒng)來(lái)說(shuō)就不是這樣了,對(duì)于routing來(lái)說(shuō)URL不需要與磁盤上的真實(shí)文件對(duì)應(yīng)甚至不需要有擴(kuò)展名。
這個(gè)新的URL路由系統(tǒng)是作為一個(gè).NET HTTP模塊創(chuàng)建的。該HTTP模塊是被假設(shè)為處理所有請(qǐng)求來(lái)創(chuàng)建的,該模塊是判斷和決定對(duì)一個(gè)請(qǐng)求的控制是否可以轉(zhuǎn)入到你的asp.net mvc項(xiàng)目的某個(gè)控制器并由該控制器來(lái)接待。但是這是.NET托管代碼,所以只有在請(qǐng)求能夠激活asp.net的條件下才能夠往下進(jìn)行(比如IIS將請(qǐng)求映射給了aspnet_isapi.dll)。所以除非該請(qǐng)求URL具有合適的擴(kuò)展名,否則aspnet_isapi.dll根本不會(huì)被激活,這意味著IIS將會(huì)把該請(qǐng)求作為靜態(tài)請(qǐng)求嘗試返回相應(yīng)于URL的靜態(tài)文件的內(nèi)容,因?yàn)榇疟P上并沒(méi)有這個(gè)靜態(tài)文件存在,所以我們將得到一個(gè)404 Not Found錯(cuò)誤。如何才能做到可以使用無(wú)擴(kuò)展名的URL呢!我們大部分希望將asp.net mvc項(xiàng)目部署到IIS6上的人開(kāi)始都會(huì)遇到這個(gè)問(wèn)題。接下來(lái)的文字中我們會(huì)給出四個(gè)解決方案以供選擇。
這篇文章主要從基礎(chǔ)和概念上介紹了asp.net mvc項(xiàng)目部署,以及IIS版本變化的情況。
【編輯推薦】