上一回合中,我們牛刀小試的在Mono中部署了我們的第一個ASP.NET應用,此外我們還結合了PostgreSQL資料庫實現了一個簡單CRUD操作的小網站。它們的成功部署並正常運行很好的體現出.NET在Linux中運作的可行性。
同時,在上回合結尾部分中提到,這回合我們將一起討論學習企業級開源架構“Spring.NET”在Mono中的部署使用。但是,最近由於個人的一些私事,一直都沒有時間對Spring.NET作出系統的學習,在這裡,我向各位讀者表示歉意。因此,在本回合中,我們學習討論的內容將發生一些變化,我們不再討論“Srping.NET”如何在Mono中部署,我們轉而討論學習跟WebForm處於平行位置的“ASP.NET MVC”如何部署到我們的Mono中,範例程式碼可以點擊這裡下載(由於代碼過大,無法上傳到園子中,所以我放到了微盤,望各位讀者見諒)。
本回合,我們將討論學習:
1、部署前的準備工作
2、從零開始,把MVC3網站應用程式程式部署到Mono中
3、從部署MVC3中啟發,把MVC4部署到Mono中
4、另外一種與前面部署方式“相逆”的MVC4部署方式
1、系統約定——部署前的準備工作
最近一段時間,許多朋友都紛紛發帖發部落格表示已經成功的在Mono中成功的部署了最新版的MVC架構,相當的喜聞樂見。MVC是什麼,我想各位讀者一定知道,它作為微軟推出的重要建站模式,其地位與WebForm相當,重要性也是不容忽視的。試想一下,如果MVC無法在Mono中部署,那我們的Linux.NET彷彿就是一隻折翼了的小鳥——“想要飛也飛不高?“不對,直接是飛不起來了。因此,MVC能夠正常的在Mono中運行似乎已經就是Linux.NET的一項”理所當然“的事情。
好的進入我們的正題,在部署MVC之前,我們需要建立一個Jexus的網站配置:
我們先在Linux中建立一個存放檔案的檔案夾,然後cd(進入)到Jexus存放網站設定檔的目錄,再建立一個本次實驗的網站設定檔”linux.net5“
添加上我們配置的內容
最後儲存退出,然後再重啟我們的Jeuxs即可。
在這裡,特別值得注意的地方:
那就是”NoFile“配置項,各位讀者一定要把此功能關閉(添加後注釋掉或直接就不添加進去,Jexus預設此功能是關閉的)。在MVC中我們的訪問路徑是經過路由重寫的,當我們發起一個訪問請求時,比如:localhost/Home/Index/,請求會經過路由的匹配並改寫,最終把請求指派到Controller檔案夾中的HomeController.cs檔案中的Index方法,然後再由該方法對請求作出處理並發出應答。在整套的MVC”請求--應答“處理過程中,瀏覽器在地址欄發起的URl請求在網站中未必都是真實的檔案物理地址訪問請求。而這恰恰相反的,在Jexus的NoFile檢測中,Jexus會對使用者發起的訪問請求(URL)進行檔案物理地址的檢測,檢測不通過時就直接對使用者應答一個預設的應答頁面(比如這裡的404頁面),不再使用.NET的功能對URl作更多的處理,因此,請求將永遠無法指派到正確的Action進行處理,整套的MVC網站也會因此而報廢。
同樣,對於一些在.NET中使用URlRewrite的網站,Jexus的”NoFile“功能也是需要關閉的,原因與MVC一樣,將會被URL重寫的請求還沒有通過Jexus這一關就被拒絕了,無法繼續的進入.NET進行處理,網站的訪問也會因此而造成一定程度的影響(這裡網站不會被報廢,因為在瀏覽器中輸入真實的物理地址,網站又可以正常的訪問)。
2、部署MVC3網站應用程式程式
Mono中部署MVC3應用程式,這不是我們本回合的終極目標,但是確實本回合最重要的內容,因為只要學會了在Mono中部署MVC3,部署MVC4也就是那麼一回事了。其實,在Mono中成功部署MVC3也不是一件新鮮的事情,早前就已經有不少成功的案例,園子中也有一些關於如何在Mono中部署MVC3的文章,各位讀者如有興趣,可以自行查閱,當然,讀者們也可以從本文中直接找到方法,我們在這裡採用的是Step By Step的討論學習方法,一步一步的說明白如何操作,並指出當中需要注意的地方和解析原因。
好的,我們先建立一個MVC3應用程式”MVC31“,並選擇”空模板“和”Razor視圖引擎“
由於這個是一個空模板,裡面沒有任何現成的Controller,我們簡單的建立一個HomeController,並添加上一個Index Action和相關的視圖。然後在windows中運行:
那是沒有問題的,但如果我們發布到Linux中,效果就不一樣了:
沒錯,正如所想的一樣,無法正常運行,按照上面的提示,我們設定”CustomError“節點,把它設定為”OFF“,重新發布,看看那裡出了問題:
第一個問題出現了,很明顯,是由於Entity Framework引起的。沒錯,如果有認真讀過我前一篇文章《Linux.NET學習手記(4)》 的讀者大概已經明白其中的原因和知道解決辦法了。正如我上回合為什麼沒有使用EF(我最喜歡的ORM)而改為使用PetaPoco的原因一樣,Mono中的EF版本已經是6.0並且還不支援低於此版本的EF架構,恰好微軟正式發布的EF版本最高只有5.0,於是這就造成了我們這裡的第一個錯誤。不過這裡的問題也只是暫時性的,隨著微軟將來EF6.0的發布,這個問題,將會得到解決。
我們通過NuGet卸載所有的Entity Framework。
然後再清除Web.Config和Global中的一些殘留項,然後再次發布。
然後順利的進入到我們的第二個問題,這裡我解釋一下出現此問題的原因,由於mono 3.0.X對語言文化的支援暫時還沒有對中文支援(2.X中則可以支援中文),因此系統預設所使用的”zh-CN“讓Mono無法識別。此問題的解決辦法就是:在WebConfig的”system.web“節點中添加上”globalization“節點,並把當中的”uiCulture“設定成”en-US“。在這裡我們推薦的配置為”<globalization culture="zh-CN" uiCulture="en-US"/>“,這樣就可以讓我們的程式本身以”英語“文法來運行,但是顯示時卻能夠以”中文“文法來顯示。
我們添加上這個節點,並重新發布:
非常不幸的,我們繼續進入到了一個新的錯誤,到這裡,各位讀者有什麼感覺了?抓狂了?想想放棄了?俗話說:”行百裡者半九十“,這時千萬別放棄,因為成功就在眼前了。通過從網上翻閱大量的資料,我們找到這這次問題的真兇,沒錯,作怪的就是”Microsoft.Web.Infrastructure.dll“,我們把Windows中”Microsoft.Web.Infrastructure.dll“和Mono中的”Microsoft.Web.Infrastructure.dll“反編譯:
可以看出,Windows中的Infrastructure和Mono中的Infrastructure還不是同一回事,那這就好辦了,我們把MVC3項目中的Infrastructure剔除,讓程式使用Mono內建的動態庫,或許就可以解決我們現有的問題。我們刪除這個動態庫後,再次發布:
終於看到了我們一直努力想要看到的”Index“,MVC3成功的在Mono中跑起來了。
趁熱打鐵,我們再結合上PostgreSQL資料庫和PetaPoco快速的建立一個CRUD的小應用。
我們先建立一個商品表”Goods“,其表結構如下:
然後在建立相關的Controller、Model、View等,這裡就不再介紹當中的代碼如何編寫和實現,有興趣的讀者可以在代碼示範中查看。
把做好的網站發布到Mono中:
頁面能夠正常顯示,沒有問題,我們在試試添加一個新的商品:
添加商品時報了一個錯,同時在“Details”中提示有一個程式集找不到。
通過排錯,我們發現了我們引用的一個DLL檔案在Mono中是沒有的:
這樣,我們只要在“C:/Windows/assembly”目錄中找到“System.ComponentModel.DataAnnotations.dll”(注意版本),然後再手動的添加到我們發布的網站中的bin目錄中即可。
再次添加資料,OK!成功添加!
出現了“Linux.NET學習手記”這個商品。至此,MVC3的簡單部署已經完成~!!
這裡做一些小提示:
(1)、由於我採用了的是虛擬機器,因此我結合了一個Linux的Samba服務來直接發布,各位讀者也可以採用Ftp或者發布到本地再上傳的方式進行網站的發布,發布後記得重啟一下Jexus。
(2)、“Infrastructure”動態庫除了可以採用發布會刪除的方式進行處理,也可以採用“不複製”的屬性才處理
(3)、讀者們也可以參考《在mono3.0.10+Jexus5.3上運行MVC4和WebApi的要點》這篇文章,上面的方法與這裡有師出同門之道。
3、Mono中部署MVC4
上一小節中,我們曆盡艱辛“取得真經”,成功的把一個MVC3網站應用程式部署到了Mono中,在這取得重要的成功之後,我們向我們本回合的終極目標繼續推進——在Mono中部署一個MVC4應用。其實,無論是MVC3還是MVC4,它們的部署方法都是類似的,我們在上小節中詳講了MVC3的部署就是為了能夠在部署MVC4起到一定的參考作用。
好的,心動不如行動,我們馬上的建立一個MVC4的網站應用程式:
然後再根據我們剛才部署MVC3的經驗步驟,進行相關的修改:
(1)、剔除所有Entity Framework的應用(使用NuGet卸載EF,並清除所有關於EF的殘留)
(2)、在Web.Conf設定檔中的“system.web”節點中加入“<globalization culture="zh-CN" uiCulture="en-US"/>”
(3)、移除“Infrastructure”這個動態庫檔案
把這個MVC4應用程式發布到Mono中:
可以正常的運行,同樣的,我們在建立一個“商品”的增刪查改,並把缺少的“System.ComponentModel.DataAnnotations.dll”補上:
同樣的實現了我們想要的功能。
通過“照葫蘆畫瓢”的方法,我們把一個MVC4的網站應用程式程式順利的部署到Mono中了,其實也就差不多而已。
4、另一種版本的MVC4部署方法
從本回合開篇起,無論是部署MVC3還是部署MVC4,我們所採用的辦法都是直接使用Visual Studio所提供的MVC模板,然後通過“哪裡不行刪哪裡”的方法,把Mono中不支援或無法直接相容的地方進行刪除或修改。可以說,我們採用了一種“逆向”的方法來獲得一個Mono支援的MVC應用。說到這裡,各位讀者可能猜到,“既然有這種逆向的方法,應該也會有一種正向的辦法來部署”。近日我讀到了一篇題目名為《嘗試在 Mono 3.0 下運行 ASP.NET MVC 4》的文章,受到了一些啟發,發現還真的有讀者們所說的“正向”方法來獲得Mono支援MVC4應用程式。那就是不使用Visual Studio所提供的MVC模板,通過為Web應用程式添加必要的MVC庫檔案的方式手動的搭建起一個MVC應用程式。
在本小節中,我們將嘗試的通告手動的方法,獲得一個Mono支援的MVC4網站應用程式程式。在參照那篇文章的同時,結合我們“逆向”部署的方法與經驗,在Mono中部署我們想要的MVC4應用程式。
首先,我們建立一個空的Web應用程式(注意,不是MVC4應用程式):
然後通過NuGet管理工具,安裝上MVC4的庫檔案:
然後在手動的建立相應的檔案夾和檔案:
這裡解析一下,有幾個檔案以及檔案夾是必須建立的:
(1)、Controller檔案夾:用於存放控制器
(2)、Views檔案夾:用於存放模版
(3)、Models檔案夾:用於存放實體類檔案
(4)、Global.asax檔案:用於應用程式啟動時初始化(註冊路由等)
在網站設定檔中添加上MVC4需要用到的一些配置:
<configuration> <appSettings> <add key="webpages:Version" value="2.0.0.0"/> <add key="webpages:Enabled" value="false"/> <add key="PreserveLoginUrl" value="true"/> <add key="ClientValidationEnabled" value="true"/> <add key="UnobtrusiveJavaScriptEnabled" value="true"/> </appSettings> <system.web> <globalization culture="zh-CN" uiCulture="en-US"/> <compilation debug="true" targetFramework="4.0" /> </system.web></configuration>
剔除會在Mono中“作怪”的“Infrastructure”動態庫檔案,然後在全域設定檔的“Application_Start ”方法中註冊上路由:
protected void Application_Start(object sender, EventArgs e){ AreaRegistration.RegisterAllAreas(); GlobalFilters.Filters.Add(new HandleErrorAttribute()); RouteTable.Routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); RouteTable.Routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } );}
手動的在Controller和View中建立控制器和模板(這裡不詳講,只需注意要繼承相應MVC類),然後再發布到Mono中:
Controller找不到頁面了,我們開啟發布後的目錄:
我們的Views檔案夾不見了。其實,這是由於我們建立的是WebForm的應用程式,發布時,我們的頁面會被嵌入到了bin目錄的程式集中,所以MVC的模版解析引擎無法在根目錄中找到VIews目錄以及裡面的所有模板。這個檔案的解決辦法也比較簡單,只需把Visual Studio中的Views檔案夾整個的拷貝到網站根目錄中即可。
再次訪問:
OK~!!正常訪問!
這裡我有一點要聲明一下,Mono的HttpRuntime是支援targetFramework的,因此我們這裡並沒有把“targetFramework”去除(跟參考文章有所不同),各位要多加留意~!!
本回合中,我們嘗試性的並成功把MVC3網站應用程式程式部署到Mono中,並根據MVC3的部署方式推演出了MVC4的部署方式,同時還介紹了相對於我們現有部署方式的Web應用程式升級為MVC4應用程式的方式部署。希望各位讀者在通讀全文之後能夠親自的動手實現一遍,“世上無難事,只怕有心人”,只要有恒心,所有的困難最終都不是困難。同時,如果各位讀者有一些更好的部署點子或對本文有任何的看法和建議,歡迎留言分享和指正。
好的,本回合暫時就到這裡了,這裡我就不作下回合的預告了,還沒有想到下回合具體會寫一些什麼。OK,咱們下回見。