本章我們將講解ASP.NET5項目發布部署相關的內容,樣本項目以我們前一章建立的BookStore項目為例。
發布前的設定
由於新版ASP.NET5支援多版本DNX運行環境的發布和部署,所以在部署之前,我們需要設定部署的目標DNX(即之前的KRE)。
步驟:右鍵BookStore項目->屬性->Application選項卡,選擇DNX的版本,本例中,選擇dnx-coreclr-win-x64.1.0.0-beta4。
在project.json檔案的commands節點,我們可以看到,系統預設配置了3個調試命令,分別如下:
| 命令 |
描述 |
| web |
啟動WebListener服務,該服務可以讓web程式脫離IIS運行,預設地址是http://localhost:5000。 |
| gen |
使用該命令可以產生MVC相關的代碼,比如Controller,目前還用不到。 |
| ef |
Entity Framework遷移命令,用於遷移資料使用,本例我們還使用者不到。 |
理論上來說,我們F5啟動並執行時候,應該是啟動web命令,但是在VS2015中,預設的運行環境依然是IIS Express,所以F5調試的時候,會預設啟動IIS Express。
gen參考:http://www.jb51.net/article/87244.htm
注意:web模式和IIS Express模式的程式運行連接埠不一樣。
我們先F5調試運行,啟動IIS Express,開啟頁面,一切正常。重新選擇預設模擬器環境為web,再F5運行,這時候發現彈出了一個命令列視窗,並提示如下文字:
[INFORMATION:Microsoft.NET.Http.Server.WebListener] Start[INFORMATION:Microsoft.NET.Http.Server.WebListener] Listening on prefix: http://localhost:5000/Started
代碼沒有出錯,但是並沒有開啟瀏覽器視窗,我們手工開啟一個瀏覽器訪問上述網址,即可看到該樣本程式的介面,此時說明,該BookStore已經成功運行在5000連接埠了。其實該模式下的瀏覽器自動開啟功能預設是關閉的,可以通過如下方式開啟自動開啟功能:
步驟:右鍵BookStore項目->屬性->Debug選項卡,勾選Launch Brower複選框,並在輸入框裡輸入上述網址即可(此時會在項目的Properties目錄下產生一個debugSettings.json檔案來儲存上述資訊)。
再次F5運行,即可看到自動開啟的瀏覽器介面。
應用程式參數
在該Debug選項卡中,我們還看到一個應用程式參數(Application Arguments)輸入框,該輸入框可以傳入多種參數,這些參數可以在Startup.cs裡,通過Configuration的AddCommandLine方法進行收集並利用。
環境變數
同理,在Debug選項卡的最下面還有一個環境變數(Environment Variables)輸入框,可以讓我們在調試的時候自訂一些環境變數的值(key/value),然後通過Configuration的AddEnvironmentVariables方法進行收集並利用。
上述參數和環境變數的具體使用方式,請參考配置資訊管理章節。
發布流程分析
在之前的MVC程式中,我們一般都是通過右鍵項目,選擇發布(Publish)的方式來發布程式的,這一次我們也來看看這種方式。
首先,右鍵->發布->Profile(選擇File System)->選擇D:\BookStore->選擇Release/coreclr->下一步,最終點擊發布。在在Output面板,我們看到出錯了,錯誤資訊如下:
正在串連到 D:\Documents\Visual Studio 2015\Projects\BookStore\BookStore\..\artifacts\bin\BookStore\Release\Publish...C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v14.0\Web\Microsoft.DNX.Publishing.targets(342,5): 錯誤 : 錯誤: 無法識別規則“BackupRule”。C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v14.0\Web\Microsoft.DNX.Publishing.targets(342,5): 錯誤 : 錯誤計數: 1。C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v14.0\Web\Microsoft.DNX.Publishing.targets(342,5): 錯誤 : An error occured during publish.The command ["C:\Program Files (x86)\IIS\Microsoft Web Deploy\msdeploy.exe" -source:contentPath='C:\Users\Administrator\AppData\Local\Temp\PublishTemp\' -dest:contentPath='D:\Documents\Visual Studio 2015\Projects\BookStore\artifacts\bin\BookStore\Release\Publish' -verb:sync -enableRule:DoNotDeleteRule -retryAttempts:2 -disablerule:BackupRule ] exited with code [-1]。
通過查看輸出資訊,可以發現,編譯成功,但複製的時候出錯,可能是powershell的問題,所以返回上述步驟,在設定(Settings)選項卡下,將解除發佈指令碼(Publish Scripts)下的使用PowerShell指令碼發布的複選框。重新發布,成功了。
開啟發布目錄D:\BookStore,發現產生了如下目錄和檔案:
| 目錄或檔案 |
描述 |
| approot |
應用程式目錄 |
| wwwroot |
靜態檔案目錄 |
| gen |
linux shell命令檔案 |
| gen.cmd |
cmd命令檔案 |
| web |
linux shell命令檔案 |
| web.cmd |
cmd命令檔案 |
看到cmd檔案的副檔名,我們可以猜想這些命令是用於執行相關的命令,比如web.cmd可能就是用於啟動程式的;而非cmd副檔名檔案,我們則猜想可能是用於linux/mac啟動並執行命令。
我們來試一下,點擊web.cmd檔案,該檔案執行以後顯示的資訊和我們在Debug程式時彈出的資訊一樣,通過訪問提示中的網址,我們可以驗證應用程式已經正常運行了。這種模式即時我們所說的自宿主(Self-Host)運行模式。
再試一下IIS是否能夠運行該程式,將IIS網站指向到wwwroot目錄,開啟網址,也是可以正常訪問的。開啟wwwroot檔案夾進行查看,靜態檔案一應俱全,但是發現bin目錄下並沒有我們的項目DLL(BookStore.dll),而是多了一個AspNet.Loader.dll,而且根目錄下還多了一個web.config檔案,內容如下:
<?xml version="1.0" encoding="utf-8"?><configuration> <appSettings> <add key="bootstrapper-version" value="1.0.0-beta4" /> <add key="runtime-path" value="..\approot\packages" /> <add key="dnx-version" value="1.0.0-beta4" /> <add key="dnx-clr" value="coreclr" /> <add key="dnx-app-base" value="..\approot\src\BookStore" /> </appSettings></configuration>
通過查詢相關資訊(訪問詳情) ,得知AspNet.Loader.dll檔案只是一個橋接檔案,用於接收IIS轉寄過來的請求,然後將其轉交給dnx進行運行,這裡的web.config裡的dnx以及項目資訊的設定檔是AspNet.Loader.dll在轉交請求時所需要的配置資訊。
通過設定檔我們可以看到,這裡配置了dnx的類型、版本號碼,程式集的路徑和app的路徑。開啟approot\src\BookStore目錄,我們發現,這裡居然都是cs源碼,雖然有個bin目錄,但是裡面也沒有dll檔案。而且在approot\packages檔案夾下,居然有90個組件檔夾(將近30M檔案)。
通過查詢網站的資料得知(這一部分內容,我們在下一節進行講解),目前真正運行程式的運行環境是DNX,也被複製到approot\packages\dnx-coreclr-win-x64.1.0.0-beta4目錄中, 而該項目依賴的所有程式集(包括System開頭的)都被複製到該packages目錄下了。目的就是要做到真正的跨平台運行,也就是說,將這些檔案複製到linux系統下,只要有對應版本的KRE(本例中的DNX是Windows版本的)的話,就可以正常運行該程式。
而bin目錄下沒有dll檔案,則是使用了微軟最新的動態編譯技術,即在啟動並執行過程中,自動編譯cs檔案,而且一旦修改這些cs檔案的話,系統將會自動再次進行編譯。(感覺有點像php等指令碼語言了)。雖然動態編譯很高效,但是還是沒有編譯好的dll高效,所以微軟還提供了一個選項讓開發人員在調試的時候產生dll檔案。具體步驟如下:
右鍵BookStore->屬性->Build選項卡,勾選編譯時間產生輸出(Produce outputs on build)複選框。
重新編譯器,發現在BookStore\artifacts\bin\BookStore\Debug目錄下的2個DNX版本檔案夾下都分別產生了BookStore.dll檔案了,而且還順帶了Nuget的spec檔案。
如果在發布的時候也要產生dll檔案,則需要在發布(Publish)設定裡進行修改,步驟如下:
右鍵BookStore->發布(Publish)->Settings選項卡->File Publish Options->勾選Precompile during publishing複選框。
這樣就可以產生響應的dll檔案, 但是這些dll檔案依然不在wwwroot/bin目錄下,而是在approot\packages\BookStore\1.0.0目錄下,在該目錄下有2個檔案夾,分別是lib和root,以及相關的Nuget的spec檔案,在lib目錄下,產生的是不同dnx版本的dll檔案,而root則是類似於之前的web根目錄,因為在該目錄下除了有視圖檔案以外,還和以前的結構一樣,保留了bin目錄,並且在bin目錄下的Release檔案夾下,也有一份針對不同dnx版本的dll檔案副本。
提示:上述選擇中,另外一個Delete all existing files prior to publish也可以勾選上,以便在發布時將之前發布版本的所有檔案全部清空。
此時,我們通過web.cmd檔案或者IIS模式來驗證發布的檔案,經驗證,均可以正常運行。再仔細對比兩份不同設在的發布檔案,發現,除了dll檔案以外,web.config檔案的應用程式路徑也變了,即從原來的:
<add key="kre-app-base" value="..\approot\src\BookStore" />
變成了如下版本:
<add key="kre-app-base" value="..\approot\packages\BookStore\1.0.0\root" />
而web.cmd檔案的內容,也從如下內容:
@"%~dp0approot\packages\dnx-coreclr-win-x64.1.0.0-beta4\bin\dnx.exe" --appbase "%~dp0approot\src\BookStore" Microsoft.Framework.ApplicationHost web %*
變成了如下內容:
@"%~dp0approot\packages\kre-coreclr-win-x64.1.0.0-beta4\bin\dnx.exe" --appbase "%~dp0approot\packages\BookStore\1.0.0\root" Microsoft.Framework.ApplicationHost web %*
上述變化,我們是可以理解的,即將src源碼動態編譯啟動並執行模式修改為先行編譯dll程式集的模式。所以,在這裡我們可以看到,在源碼動態編譯模式下,其發布後的檔案夾結構如下:
//源碼動態編譯模式wwwroot/bin/Microsoft.AspNet.Loader.IIS.dllwwwroot/Contents/site.csswwwroot/Contents/...............................................................................................wwwroot/Scripts/jquery.jswwwroot/Scripts/........................................................................................................................................................approot/src/BootStore/project.jsonapproot/src/BootStore/...............................approot/src/BootStore.Data/project.jsonapproot/src/BootStore.Data/..............................approot/src/BootStore.Bussiness/project.jsonapproot/src/BootStore.Bussiness/.........................approot/packages/Elmah/{version}/...............................................................................
而dll先行編譯模式下的發布檔案夾結構如下:
//dll先行編譯模式wwwroot/bin/Microsoft.AspNet.Loader.IIS.dllwwwroot/Contents/site.csswwwroot/Contents/...............................................................................................wwwroot/Scripts/jquery.jswwwroot/Scripts/........................................................................................................................................................approot/packages/BootStore/{version}/...................approot/packages/BootStore.Data/{version}/..............approot/packages/BootStore.Bussiness/{version}/.........approot/packages/Elmah/{version}/.......................
IIS和web.cmd模式的不同
雖然我們對dnx內容的原理不太理解,但有一點內容,我們要記住,那就是兩種模式下,對靜態檔案的訪問模式可能不太一樣。原因是因為,雖然IIS模式的根目錄就是存放靜態檔案的地方,但是web.cmd檔案事先啟動的卻是approot\src\BookStore目錄或approot\packages\BookStore\1.0.0\root目錄,兩個目錄下均沒有靜態檔案,因為靜態檔案時在wwwroot目錄下的,我們猜想,在這種模式下,肯定會有一種機制在來映射這些靜態檔案,通過尋找檔案發現,在approot\src\BookStore目錄下的project.json檔案中的webroot鍵的值,從解決方案中預設的wwwroot變成了"../../../wwwroot",也就是說kre在映射靜態檔案的時候,應該是根據這個相對目錄來尋找這些檔案的。
同理,approot\packages\BookStore\1.0.0\root目錄下的project.json檔案中的webroot鍵的值,也從wwwroot變成了"../../../../../wwwroot"(因為本來project.json檔案的層級就深)。
由於IIS是通過AspNet.Loader.dll做中轉,將請求轉交給DNX來啟動並執行,那麼在IIS模式下,靜態檔案的請求到底是IIS來處理,還是KRE來處理呢?我們來驗證一下,驗證步驟如下:
建立一個wwwroot2檔案夾和wwwroot同級,並將wwwrooot目錄下的靜態檔案剪下到wwwroot2目錄下。將project.json(如果是先行編譯模式,則需要修改root目錄下的project.json)檔案中的webroot值中的wwwroot修改為wwwroot2。繼續以IIS模式運行該網站
結果發現,靜態檔案訪問不了了(CSS、JS、Images均失效了),但我們再通過web.cmd運行時,這些靜態檔案卻又可以訪問了。由此得知,在IIS模式下,靜態檔案走的是IIS的管線Pipeline,而不是DNX的關係Pipeline。
兩種發布模式下的project.json檔案不同
動態編譯模式和先行編譯dll模式這兩種模式的自動發布程式,產生後的project.json檔案有一些變化,具體變化如下。
動態編譯模式
基本上和解決方案裡的project.json檔案相同,唯一的不同就是webroot的相對路徑的修改。
先行編譯dll模式
原來引用的眾多程式集從dependencies節點中移除了,取而代之的是BookStore程式集引用,樣本如下:
"dependencies": { "BookStore": "1.0.0"},
另外,還多了如下兩個節點值(具體功能暫不明確):
"entryPoint": "BookStore","loadable": false
猜想,這些不同,可能是因為在動態編譯模式下需要引用這些被移除的程式集進行編譯,而先行編譯dll模式下,都已經編譯好了,所以就不再需要這些程式集了,而root目錄只需要引用BookStore程式集就可以了,而BookStore程式集對這些程式集的依賴,詳細在該dll程式集的nupkg檔案裡是可以自動解析並下載的吧(這一點待驗證)。
以上是新版ASP.NET5項目在發布流程和相關技術的一些內容,從這裡大家可以看到,ASP.NET5是徹底模組化了,IIS不再是運行MVC程式的唯一容器,任何相容DNX的運行容器都可以運行MVC程式,程式發布包被分為approot和wwwroot兩個部分,分別存放應用程式集(或源碼)和靜態檔案,從而做到更好的分離。在下一章,我們會討論,ASP.NET 5的運行原理。
注意:目前還沒有辦法通過複製源碼的形式來進行調試,同時也沒辦法將IIS指向到源碼中進行調試,這將會改變開發人員的開發習慣。