淺談 ASP.NET Core 中的環境名稱設定與應用
起因是同事對於 ASP.NET Core 的發佈不太熟悉,而我也有一些細節搞錯,所以想寫一篇文章來整理相關內容。
組態設定
在過往的 .NET Framework 中,主要用組態設定來切換不同的設定檔。詳細內容可以參考「在 .NET Framework 裡,有關 Web.config (App.config) 的應用」。使用 Web.config 為主檔,透過 Web.{組態}.config 來覆蓋 Web.config 的內容。在每個組態中,可以定義相應的常數,並使用條件式編譯進行切換。
環境名稱
在 .NET Core 和 .NET 5 及之後的版本中,除了組態設定外,還增加了環境變數 EnvironmentName 來區分不同的環境。EnvironmentName 可以是任何值,但 ASP.NET Core 預設提供以下值:
- Development:本機開發使用。
- Staging:預發佈版本
- Production:如果未設定
DOTNET_ENVIRONMENT和ASPNETCORE_ENVIRONMENT,則為預設值,一般做為正式機版本使用。
這三個環境名稱可以對應到 GitLab Flow 的 master、pre-production 和 production 分支。如果 GitLab Flow 定義了其他環境分支,也可以設定相應的環境名稱。
在 ASP.NET Core 中,主要使用 appsettings.json 作為設定檔,並使用 appsettings.{環境}.json 來覆蓋主要設定檔的內容。與過往 Web.config 的不同之處在於,Web.config 使用 Web.{組態}.config 進行 Transform 的替換機制,建置後產生新的 Web.config;而 appsettings.json 則是依照載入順序,後載入的設定會覆蓋之前的設定。
當 ASP.NET Core 執行 WebApplication.CreateBuilder(args) 時,內部會呼叫擴充方法 HostingHostBuilderExtensions.ConfigureDefaults(),並載入 appsettings.json 和 appsettings.{環境}.json。以下節錄部分程式碼:
builder.ConfigureAppConfiguration((hostingContext, config) => {
IHostEnvironment env = hostingContext.HostingEnvironment;
bool reloadOnChange = GetReloadConfigOnChangeValue(hostingContext);
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: reloadOnChange)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: reloadOnChange);
if (env.IsDevelopment() && env.ApplicationName is { Length: > 0 }) {
var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));
if (appAssembly is not null) {
config.AddUserSecrets(appAssembly, optional: true, reloadOnChange: reloadOnChange);
}
}
config.AddEnvironmentVariables();
if (args is { Length: > 0 }) {
config.AddCommandLine(args);
}
})WARNING
由於 ASP.NET Core 內部已經會載入 appsettings.json 和 appsettings.{環境}.json,如果再手動載入 appsettings.json 可能會覆蓋 appsettings.{環境}.json 的設定。我之前就曾因不明原因沒讀取到 appsettings.{環境}.json,又被 Web.config 的思維誤導,在 Program 裡加入這兩行做測試,然後嘗試註解引用 appsettings.{環境}.json,一直疑惑為何沒吃到設定,後續看同事把兩行都註解掉測試,才發現哪邊有問題。
設定環境變數的方法
本機開發
ASP.NET Core 可以在「Properties\launchSettings.json」檔案中設定本機開發環境。此設定的環境值會顯示在 Visual Studio 的模擬器列表上,並會覆蓋全域環境設定。以下為預設範例,更多具體設定請參考 MSDN 的「開發和 launchSettings.json」。
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:59481",
"sslPort": 44308
}
},
"profiles": {
"Sample": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:7152;http://localhost:5105",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}使用 Visual Studio 發佈
發佈方式請參考之前文章的 Web 專案發佈,雖然當時是寫 ASP.NET 版本,但 ASP.NET Core 操作方式相同,唯一的不同是需要在 XML 裡加上以下內容來設定環境名稱:
<EnvironmentName>Staging</EnvironmentName>發佈後,會在 Web.config 增加以下內容,IIS 會以此內容作為環境變數的值:
<?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=".\KunYou.KyFido.Backend.WebApi.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="inprocess">
<!--額外產生內容設定-->
<environmentVariables>
<environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Development" />
</environmentVariables>
</aspNetCore>
</system.webServer>
</location>
</configuration>TIP
過往在 ASP.NET 設定 Publish.xml,可以設定 <ExcludeFilesFromDeployment> 或 <ExcludeFoldersFromDeployment> 來排除特定檔案或資料夾,但是在 ASP.NET Core 中此設定無效,所以無法用此排除多餘的 appsettings.{環境}.json 檔案。
使用 Dockerfile 設定
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
# 增加此行設定環境變數
ENV ASPNETCORE_ENVIRONMENT=Staging操作環境設定
ASP.NET Core 使用 IWebHostEnvironment 物件定義環境相關操作。此介面實作的 IHostEnvironment 定義了屬性 EnvironmentName。此外,在 HostEnvironmentEnvExtensions 中定義了擴充方法 IsDevelopment()、IsStaging() 和 IsProduction(),以便在執行階段判斷目前的環境名稱。如果是自定義的環境名稱,可以使用 IsEnvironment({environmentName}) 來判斷。
異動歷程
- 2024-07-12 初版文件建立。
