解讀ASP.NET 5 & MVC6系列(3):專案釋出與部署
本章我們將講解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.cnblogs.com/dudu/p/aspnet5-k-gen.html
注意: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.dll
wwwroot/Contents/site.css
wwwroot/Contents/.......................................
........................................................
wwwroot/Scripts/jquery.js
wwwroot/Scripts/........................................
........................................................
........................................................
approot/src/BootStore/project.json
approot/src/BootStore/...............................
approot/src/BootStore.Data/project.json
approot/src/BootStore.Data/..............................
approot/src/BootStore.Bussiness/project.json
approot/src/BootStore.Bussiness/.........................
approot/packages/Elmah/{version}/.......................
........................................................
而dll預編譯模式下的釋出資料夾結構如下:
//dll預編譯模式
wwwroot/bin/Microsoft.AspNet.Loader.IIS.dll
wwwroot/Contents/site.css
wwwroot/Contents/.......................................
........................................................
wwwroot/Scripts/jquery.js
wwwroot/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指向到原始碼中進行除錯,這將會改變開發人員的開發習慣。