在 IIS 上執行 ASP.NET Core


雖然,ASP.NET Core 的程式可以單獨執行(使用內建 kestrel 伺服器),但是 kestrel 畢竟是輕量化服務器,操作與設定不熟悉的人使用起來就會頗困難。

而且,在有規模公司裡面伺服器 IIS 管理人可能又跟寫這程式碼的人不是同一個人,因此大原則上,程式設計就歸程式設計,伺服器管理就歸伺服器管理是比較標準的做法。

那麼 IIS 上如何掛上 ASP.NET Core 的應用呢?

建議使用 IIS 8.0 以上的版本(官方建議啦),原則上就是 Server 2008 以上作業系統。

一、下載執行環境套件 Runtime :

Microsoft Visual C++ 2015 Redistributable (非必要,除非該機器沒有裝過,下載要注意X86或X64版本)
.NET Core Runtime (注意你的SDK版本)

在下載 .NET Core Runtime 時,一般都是下載最新版即可,如下圖:


但是如果你的SDK(開發)版本差異太大,例如你使用 SDK 2.0,而 Runtime 使用 2.1 ,則可能發生程式無法執行的錯誤,建議更新 SDK 後再重新編譯程式放到伺服器上,不然就是安裝降版的 Runtime ,若要安裝其它版本 Runtime,請點選下面聯結,尋找適當版本的 Runtime:

選擇其他版本,例如 2.0 版

下載該版本的 Runtime



二、在伺服器上,將 Microsoft Visual C++ 2015 Redistributable 與 .NET Core Runtime 安裝好。

三、建立程式放置資料夾與設定權限,如果直接使用 IIS 的內定資料夾 C:\inetpub 者,則省略此步驟。我再這個案例是建立在 D:\inetpub\api ,所以必須增加資料夾使用權限給 IIS 使用。

四、在IIS管理員裡面新增應用程式集區
        名稱雖然可以自己訂,但要易於識別所以取名為 .NET Core,然後 .NET CLR 版本要選『沒有Managed程式碼』(Unmanaged Code)。


五之一、新增站台方式(如果要繼續使用80port做為http的服務,請確認原本IIS的站台 Default Web Site已經是停止狀態,若沒停止則請停用,否則 80 port將被占用無法使用)



站台名稱只是用來識別,取個好記的即可,應用程式集就要選我們剛剛設訂的『.NET Core』,然後實體路徑就選擇程式放置的位置。

確定後只要啟動該網站即可,(如果出現連接埠80被其他綁訂問題,大可不用理會,因為它是被Default Web Site綁訂的,但是我們已經在一開始就把它停用了,所以不影響)

五之二、如果不想新增站台,而是想以『新增應用程式』方式處理,則使用下面步驟:
        在原本站台(目前是使用預設的Default Web Site)上選擇『新增應用程式』



這裡要注意的是別名,這個名稱會影響到URL上的路徑位置,如下圖。
應用程式集區一樣要選用『.NET Core』,實體路徑依然選用程式放置位置。


六、編譯程式(我因為使用 Visual Studio Code,所以要自己下指令編譯,如果您是使用 Visual Studio 2017或是 web deploy等工具不在此列,這邊是用直接拷貝編譯封裝好的檔案到伺服器上)
●編譯方式有兩種:
    ○ CLI 執行檔(DLL):

        在專案路徑下使用 dotnet publish -c release

如果有錯誤訊息,請先修正錯誤訊息。
此處編譯後會建立 release 資料夾,裡面最後的 publish 資料夾就是要放上伺服器的檔案。


注意到這裡只有 DLL 檔案,所以實際執行時是配合 dotnet.exe 執行。

把這些檔案放上伺服器後,理論上就可以執行,所以我們就執行看看吧!結果....

出現了HTTP Error 502.5 - Process Failure !!!

這是怎麼回事?
查看事件檢視器會發現錯誤,其訊息大概像這樣

Application 'MACHINE/WEBROOT/APPHOST/DEFAULT WEB SITE/API' with physical root 'D:\inetpub\api\' failed to start process with commandline 'dotnet .\SimplyApi.dll', ErrorCode = '0x80070002 : 0.

其實,這是因為 web.config 裡面的設定問題,在 Server 上打開 web.config 看到如下:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <location path="." inheritInChildApplications="false">
    <system.webServer>
      <handlers>
        <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
      </handlers>
      <aspNetCore processPath="dotnet" arguments=".\SimplyApi.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" />
    </system.webServer>
  </location>
</configuration>


重點在紅色字的地方,執行時會組合指令成為:

dotnet .\SimplyApi.dll


因為它在IIS環境下無法找到 dotnet.exe真實位置,導致無法執行,因此把 web.config 改成如下

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <location path="." inheritInChildApplications="false">
    <system.webServer>
      <handlers>
        <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
      </handlers>
      <aspNetCore processPath="C:\Program Files\dotnet\dotnet" arguments=".\SimplyApi.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" />
    </system.webServer>
  </location>
</configuration>


就可以正常執行了。

注意此處編譯的SDK版本不可以和伺服器上Runtime版本差異太大,否則會執行失敗。

    ○ EXE 獨立部屬檔:

        此種編譯封裝特性,可以不管伺服器上的 .NET Core Runtime 版本,不像 DLL 型式需要依賴 dotnet.exe 來執行。缺點是因為要獨立執行,所以需要指定目標平台RID,而且會把第三方所有套件都包進來,封裝後檔案可能高達 20~50MB甚至以上的大小。

        在專案路徑下執行 dotnet publish -c release -r win81-x64
        ※win81-x64是目的伺服器平台版本。


編譯封裝後,會產生對應 win81-x64 資料夾(這個資料夾會因為指定 RID不同產生不同資料夾。這資料夾內有 publish 資料夾,裡面就是要全部搬上伺服器的檔案。

通常裡面會有一個執行檔,這個就是要執行的目標


所以,看看它的 web.config 會發現不同

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <location path="." inheritInChildApplications="false">
    <system.webServer>
      <handlers>
        <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
      </handlers>
      <aspNetCore processPath=".\SimplyApi.exe" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" />
    </system.webServer>
  </location>
</configuration>


看!它直接執行那個執行檔而已。



留言

這個網誌中的熱門文章

【研究】列印的條碼為什麼很難刷(掃描)

C# 使用 Process.Start 執行外部程式

統一發票列印小程式