【續集】在 IIS 中部署 ASP.NET 5 應用程序遭遇的問題

針對 IIS 部署 ASP.NET 5 應用程序的問題,在上面博文中主要採用兩種方式嘗試:

  1. VS2015 的 Publish 方式(成功)。

  2. 手動複製文件的方式(失敗)。

本篇博文主題:

  1. 初步理解 ASP.NET 5 的編譯及部署問題。

  2. 解決 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 項目:

142044235587081.png

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 發佈文件結構:

142107056208797.png

approot 爲程序文件及程序包目錄,packages 下面是整個應用程序運行所需要的程序包,src 爲程序源代碼目錄,wwwroot 爲站點目錄(我們等下 IIS 部署的時候,就是指向的這個目錄),裏面有一個 bin 目錄(只有一個 AspNet.Loader.dll)和一個 web.config 文件(裏面主要配置一些地址路徑,比如程序包的地址路徑)。web.cmd 是批處理文件,它其實就是我們在 commands 中制定的命令(還可以配置 EF 遷移的命令)。

142116091201222.png

上面是本地運行結果(注意,我並沒有安裝 IIS),你也可以直接點擊 web.cmd 來啓動站點。

既然本機運行沒問題,那我們就把它發佈到 IIS 上試試,但是卻報下面的錯誤:

142126230899751.png

錯誤信息: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”:

142130181513804.png

然後把發佈生成 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 默認是“動態編譯”的,如果想設置成預編譯,需要我們手動設置一下:

142140003703300.png

在項目屬性頁的 Build 選擇中,把“Produce outputs on build”打勾就可以了,HelloClassLibrary 類庫項目同樣這樣設置,設置好了,重新生成項目,生成的程序集目錄爲:\HelloAspNet5\artifacts\bin\HelloAspNet5\Debug,在相應目錄下,就會看到我們想要的兩個程序集文件:HelloAspNet5.dll 和 HelloClassLibrary.dll,既然項目程序集生成成功,那部署應該沒有什麼問題,但 dudu 已經嘗試過,是失敗的,問題出在哪?直接把相應的程序集文件拷貝過去不行嗎?當然不行,因爲我們使用 VS2015 Publish 的時候,運行環境是“動態編譯”,那怎麼使 Pulish 的時候預編譯呢?答案就在下面:

142150448392579.png

在 Publish 的時候,還有一個發佈選項“Precompile during publishing”,就是配置預編譯的,重新發布一下,你會發現在 packages 目錄下多了兩個文件夾:

142156570261772.png

這就是預編譯生成的項目文件地址,我們再來看下 HelloAspNet5 的文件目錄:

142159322143029.png

一個是 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 上也這樣搞,但是卻出現了下面的錯誤:

142211017293844.png

錯誤信息: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 完全的組件化,不只是開發,部署也是如此,這樣的結果就是充滿着無限可能,看我七十二變!!!


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章