dudu 的一篇博文:在 IIS 中部署 ASP.NET 5 應用程序遭遇的問題
針對 IIS 部署 ASP.NET 5 應用程序的問題,在上面博文中主要采用兩種方式嘗試:
- VS2015 的 Publish 方式(成功)。
- 手動復制文件的方式(失敗)。
本篇博文主題:
- 初步理解 ASP.NET 5 的編譯及部署問題。
- 解決 ASP.NET 5 預編譯,并成功部署到 IIS 上。
先啰嗦兩句:
首先,現在的 IIS 對于 ASP.NET 5 來說,其實已經沒有太大的關系了,用不用它都無所謂,ASP.NET 5 應用程序可以采用 Self-Hosting(自寄宿)的方式,也就是自己當作 Web 服務器,實現方式只要在 project.json 中添加 Microsoft.AspNet.Hosting 程序包就可以了,我們知道,Web 服務器的作用其實就是監聽請求,并分發請求給相應模塊進行處理,最后再輸出處理結果,如果我們把這個請求處理過程進行分化,交給不同的組件或模塊進行處理,我們就可以脫離集成化的 IIS,在 Owin 體系結構中,ASP.NET 5 應用程序部署到 IIS 上,這個 IIS 的作用就只是一個 Host(管理應用程序的線程,打開、關閉或加載組件),Server(如 Microsoft.AspNet.Server.WebListener)和 Middleware(如 Microsoft.AspNet.StaticFiles)都有相應的處理組件,不需要用到 IIS 的那一套東西,比如之前我們需要在 IIS 中進行 HttpModule 配置等。
既然我們不使用 IIS 的那一套東西,如果將 ASP.NET 5 應用程序部署到 IIS 上,那就必須有個東西將 IIS 和 ASP.NET 5 獨立運行時(KRE)之間的通道(Pipeline)打通,這個東西就是 AspNet.Loader.dll(位置:application/wwwroot/bin),使用它的條件是在 project.json 中添加 Microsoft.AspNet.Server.IIS 程序包,而且只在 IIS 中才會出現,如果采用的是 Self-Hosting 方式,這個程序集將會“消失”,關于 AspNet.Loader.dll,一篇非常好的解答文章:AspNet.Loader.dll – what is this for?
另外,在 IIS 中部署 ASP.NET 5 應用程序,不像我們之前的方式,直接把相應的文件和程序集拷貝到站點目錄下,因為你會發現,在生成 ASP.NET 5 項目的時候沒有生成對應的程序集,只是在 Bin 目錄下有一個 AspNet.Loader.dll,dudu 已經試過在 ASP.NET 5 項目屬性頁的 Build 選項中,把“Produce outputs on build”選項打勾,就會生成相應的程序集文件(位置:../application/artifacts/bin),既然有了程序集,那是不是就可以像之前部署站點的方式進行操作呢?答案當然不是,這也就是為什么手動復制文件會失敗,因為 ASP.NET 5 并沒想象中的那么簡單,呵呵,采用 VS2015 的 Publish 方式部署是成功的,那我們就從它下手,觀察下它到底是怎么回事,dudu 沒做完這步,我們下面接著做。
言歸正傳
用 VS2015 創建一個簡單的 ASP.NET 5 項目:
project.json 配置:
{
"webroot": "wwwroot",
"version": "1.0.0-*",
"exclude": [
"wwwroot"
],
"dependencies": {
"Microsoft.AspNet.Server.IIS": "1.0.0-beta1",
"Microsoft.AspNet.Server.WebListener": "1.0.0-beta1",
"HelloClassLibrary": "1.0.0-*"
},
"commands": {
/* Change the port number when you are self hosting this application */
"web": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:5000"
},
"frameworks": {
"aspnet50": { },
"aspnetcore50": { }
}
}
Startup.cs 代碼:
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Http;
namespace HelloAspNet5
{
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.Run(context => context.Response.WriteAsync("Hello, ASP.NET 5 world! \{HelloClassLibrary.TestClass.testContent}"));
}
}
}
為了演示 ASP.NET 5 與依賴類庫之間的關系,我們還創建了一個 HelloClassLibrary 項目,并在 Startup 中進行調用。在 project.json 中配置 commands 是為了方便我們通過 Publish 發布出來的程序檢測是否可以正常運行。
Publish 發布文件結構:
approot 為程序文件及程序包目錄,packages 下面是整個應用程序運行所需要的程序包,src 為程序源代碼目錄,wwwroot 為站點目錄(我們等下 IIS 部署的時候,就是指向的這個目錄),里面有一個 bin 目錄(只有一個 AspNet.Loader.dll)和一個 web.config 文件(里面主要配置一些地址路徑,比如程序包的地址路徑)。web.cmd 是批處理文件,它其實就是我們在 commands 中制定的命令(還可以配置 EF 遷移的命令)。
上面是本地運行結果(注意,我并沒有安裝 IIS),你也可以直接點擊 web.cmd 來啟動站點。
既然本機運行沒問題,那我們就把它發布到 IIS 上試試,但是卻報下面的錯誤:
錯誤信息:Couldn't find package 'KRE-CLR-amd64.1.0.0-beta1'. Locations probed,什么意思?本機是 32 位系統,服務器是 64 位系統,發布設置我們選的是“KRE-CLR-x86.1.0.0-beta1”,不報錯才怪,重新更改發布設置為“KRE-CLR-amd64.1.0.0-beta1”:
然后把發布生成 HelloAspNet5.Web\approot\packages\KRE-CLR-amd64.1.0.0-beta1 下的文件,添加到服務器相應目錄下,重新刷新瀏覽器,運行成功:
Hello, ASP.NET 5 world! HeiHei
上面這些操作其實 dudu 已經完成了,并且也是成功的,但這并不是我們想要的,因為這時候,服務器運行的程序是“動態編譯”的,程序代碼地址就在 HelloAspNet5.Web\approot\src 目錄下,里面直接是源代碼,并不是生成的程序集文件,那該如何“預編譯”我們的 ASP.NET 5 應用程序呢?
首先,我們需要生成我們的應用程序,就像我們之前的 ASP.NET 應用程序一樣,而 ASP.NET 5 默認是“動態編譯”的,如果想設置成預編譯,需要我們手動設置一下:
在項目屬性頁的 Build 選擇中,把“Produce outputs on build”打勾就可以了,HelloClassLibrary 類庫項目同樣這樣設置,設置好了,重新生成項目,生成的程序集目錄為:\HelloAspNet5\artifacts\bin\HelloAspNet5\Debug,在相應目錄下,就會看到我們想要的兩個程序集文件:HelloAspNet5.dll 和 HelloClassLibrary.dll,既然項目程序集生成成功,那部署應該沒有什么問題,但 dudu 已經嘗試過,是失敗的,問題出在哪?直接把相應的程序集文件拷貝過去不行嗎?當然不行,因為我們使用 VS2015 Publish 的時候,運行環境是“動態編譯”,那怎么使 Pulish 的時候預編譯呢?答案就在下面:
在 Publish 的時候,還有一個發布選項“Precompile during publishing”,就是配置預編譯的,重新發布一下,你會發現在 packages 目錄下多了兩個文件夾:
這就是預編譯生成的項目文件地址,我們再來看下 HelloAspNet5 的文件目錄:
一個是 lib 目錄,里面就是生成的程序集文件,root 是程序的其他類型文件,比如 MVC Views 文件就在這里,而不是在 wwwroot 目錄下。另外一個非常重要的地方就是,wwwroot 下的 web.config 變成了:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="kpm-package-path" value="..\approot\packages" />
<add key="bootstrapper-version" value="1.0.0-beta1" />
<add key="kre-package-path" value="..\approot\packages" />
<add key="kre-version" value="1.0.0-beta1" />
<add key="kre-clr" value="CLR" />
<add key="kre-app-base" />
</appSettings>
</configuration>
好像也沒怎么變化?跟之前的自習對比一下,會發現 key(kre-app-base)的 value 值不見了,之前的配置為
<add key="kre-app-base" value="..\approot\src\HelloAspNet5" />
看到這你應該懂了,沒錯,你可以把 approot\src 目錄下的 HelloAspNet5 源代碼文件刪掉了,使用 k web 命令重新啟用項目,運行成功:
Hello, ASP.NET 5 world! HeiHei
接著我們重新在服務器的 IIS 上也這樣搞,但是卻出現了下面的錯誤:
錯誤信息:Couldn't find package 'KRE-CLR-amd64.1.0.0-beta1',找不到“KRE-CLR-amd64.1.0.0-beta1”程序包,在 approot\packages 目錄下明明就有啊,查看下面的提示發現 IIS 并沒有從這個目錄下進行查找,怎么辦?手動配置一下:
<add key="kre-app-base" value="..\approot\packages\HelloAspNet5\1.0.0\root"/>
需要注意的是,要配置到 root 目錄下,重新啟動項目,運行成功:
Hello, ASP.NET 5 world! HeiHei
我們接下來修改代碼,然后通過編譯程序集上傳到 IIS 服務器。
app.Run(context => context.Response.WriteAsync("Hello, ASP.NET 5 world!!! \{HelloClassLibrary.TestClass.testContent}"));
public static string testContent = " HeiHeiHei";
可以看出,上面代碼和之前的代碼是有些不同的,之前有說過使用 VS2015 編譯的程序集地址為 artifacts,我們把相應的程序集文件上傳到服務器的 approot\packages 目錄下,奇怪的事,我運行后發現改的代碼并沒有效果,還是之前的,這個問題搞了我很久,都快被搞死了,我以為是生成的程序集文件有問題,沒有生成最新的,就各種設置生成測試,最后還是沒有成功,然后無意間把 IIS 站點停掉,然后再進行上傳程序集文件,最后再啟動站點,刷新瀏覽器,你猜怎么著?Oh, My God !!!,居然出現了:
Hello, ASP.NET 5 world!!! HeiHeiHei
最后再啰嗦兩句:
從上面整個配置過程中可以看出,ASP.NET 5 是如何在 IIS 進行運行的(只是從 Publish 上來看),首先,站點目錄為 wwwroot,包含一個 bin 目錄的 AspNet.Loader.dll 文件(用來打通 IIS 和 Owin 組件之間的管道),還有一個 web.config 文件(主要配置程序包及應用程序路徑地址),除此之外,還有一些靜態文件(如 css、js 和圖片文件),如果是動態編譯站點,默認直接運行 approot\src 目錄下的源代碼文件,如果是預編譯站點,根據 kre-app-base 的路徑配置(如 approot\packages\HelloAspNet5\1.0.0\root),運行 ASP.NET 5 運行程序,注意在 root\project.json 文件中,有如下配置:"webroot": "..\..\..\..\..\wwwroot",這個指向的地址就是 IIS 站點。。。
其實,上面雖然只是一個簡單的 IIS 部署過程,但涉及到非常多的東西,也有很多的感觸,或許有些沒表達出來,總的來說,這次部署給我最重要的感受是:ASP.NET 5 完全的組件化,不只是開發,部署也是如此,這樣的結果就是充滿著無限可能,看我七十二變!!!
其他相關資料:
- AspNet.Loader.dll – what is this for?
- DEVELOPING AND SELF-HOSTING SIMPLE ASP.NET VNEXT APPLICATION USING COMMAND LINE TOOLS
- Introducing the ASP.NET 5 Preview
- A First Look at ASP.NET vNext
- ASP.NET Internals – Managed runtime loader
- Possible ASP.NET 5 (vNext) Deployed Folder Structure(With and Without Source)
- ASP.NET 5 on Azure Websites
- Cant get a basic ASP.Net 5 website working on Azure
- How to disable source code publishing in ASP.NET 5 apps?
文章列表