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

















