aspnet core publish and environment

因為對於 dotnet 的 publish 以及環境變數的設定,一直都有點混淆,所以這邊就來整理一下。

佈署到哪裡? IIS 還是 Kestrel?

在 ASP.NET Core 中,我們可以使用 Kestrel 作為 Web Server,也可以使用 IIS 作為 Web Server。
而執行 dotnet publish的時候,其實就是將專案編譯成一個可執行的檔案,並且將相關的資源檔案一起打包成一個資料夾,這個資料夾就是我們要佈署的檔案。

dotnet publish的時候預設會產出一個web.config給 IIS 使用,也就是說如果要佈署到 IIS,那麼在 dotnet publish的時候必須要加上環境變數設定的指令, web.config才會有環境變數

1
dotnet publish -c Debug -p:EnvironmentName=Development
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<location path="." inheritInChildApplications="false">
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
</handlers>
<aspNetCore processPath="dotnet" arguments=".\api1.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="inprocess">
<environmentVariables>
<environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Development" />
</environmentVariables>
</aspNetCore>
</system.webServer>
</location>
</configuration>

Ref:如何透過 dotnet publish 調整 ASP․NET Core 部署到 IIS 的 Web.config 內容

那麼環境變數需要設置的是那些東西,又影響什麼呢?

環境主要用來配置跟環境相關的一些設定值,例如連線字串、NAS 儲存空間的路徑、LOG 紀錄層級等等。設定好環境變數,在應用程序中就可以使用指定的環境(”myhome”)來載入對應的設定文件(如 appsettings.myhome.json)。而在實際上發佈出去的檔案內,也會包含著各個環境的設定檔案,例如 appsettings.myhome.json、appsettings.company.json、appsettings.home.json 等等。
這些檔案會等到實際上執行的時候,再去讀取對應的設定檔案,並且載入到應用程序中。

環境變數設定檔案並不會以實體的方式合併,而是在執行時,會依照環境變數的設定,去讀取對應的設定檔案,並且載入到應用程序中。

那麼版本又是怎麼影響佈署的呢?

版本可能會有開發版本、正式版本等差異,主要的判斷依據就是以功能來區分,雖然這些區分的方式,可以透過環境變數來做,但是如果是在開發階段,可能會有一些功能是還沒有完成的,但是又想要測試,這時候就可以透過版本來做區分。假設我在 Debug 環境需要紀錄完整的資訊,於是可能透過條件式編譯來額外紀錄一些資訊,但是在 Release 環境下,就不需要紀錄這些資訊,這時候就可以透過版本來做區分。

dotnet publish的時候會發現我們若指定了版本,那麼編譯出來的 appsettings.json 的內容,就會是合併了版本、預設的 appsettings.json 的內容。

我們可以來測試一下,首先將專案設定擋像下面這樣設定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// appsettings.json
{
"my_version": "default"
}

// appsettings.Debug.json
{
"my_version": "debug"
}

// appsettings.Release.json
{
"my_version": "release"
}

接著發布之後直接查看 appsettings.json 的內容,可以發現內容是合併了版本、預設的 appsettings.json 的內容。

1
2
3
4
5
@rem 將檔案編譯輸出到 myoutput 資料夾
dotnet publish -c Debug -o myoutput

@rem 查看 appsettings.json 的內容
type myoutput/appsettings.json


可以看到結果是 “my_version”: “debug”

那麼環境變數與版本的優先權是怎麼樣的呢?

實際上 publish 的版本已經被合併到 appsettings.json了,此時,就只剩下了環境變數的設定、以及合併完預設、版本的設定。執行的時候會先去抓appsettings.json的內容,然後也依據環境變數的設定,到對應的檔案中尋找是不是有對應的設定值,有的話就使用,沒有的話就是使用預設的設定值。

假設目前在伺服器上面的設定檔案如下

1
2
3
4
5
6
7
8
9
10
11
// appsettings.json
{
"my_version": "debug",
"my_conn": "empty"
}

// appsettings.Lab.json
{
"my_conn": "lab connection string"
}

此時應用程式若要取得 my_version 的值,則會是 debug;而若要取得 my_conn 的值,則會是 lab connection string

ReCap

  1. 環境變數設定檔案並不會以實體的方式合併,而是在執行時,會依照環境變數的設定,去讀取對應的設定檔案,並且載入到應用程序中。
  2. publish 的時候,會將版本合併到 appsettings.json 中。
  3. 環境變數的設定,會優先於 appsettings.json 的設定。
  4. dotnet publish -c <版本> -p:EnvironmentName=<環境變數> (此時指定環境變數是為了讓 IIS 使用)

補充

微軟官方提供的教學:ASP.NET Core 的設定,內容非常詳盡,有興趣的可以看看。