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

其實我們在透過 `dotnet publish` 發行 ASP․NET Core 網站時，預設都會自動發佈一個 `web.config` 檔案，但是事實上這個檔案跟 Kestrel 完全沒關係，這個檔案主要是給 IIS 看的，當你想部署 ASP․NET Core 到 IIS 的時候，就一定需要這個檔案。今天這篇文章我就來說說，如何在執行 `dotnet publish` 命令的時候，自動調整 ASP․NET Core 部署到 IIS 的 `web.config` 內容。

![6563984](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/a2728f8b46903bdeefa0-228877969-afc4ef64-ce09-4ad9-ae40-ffafd6f40a2f.jpg)

### 預設的 Web.config 內容

預設的發行任務，搭配 `-o DIR` 可以將發行後的檔案輸出到指定路徑下：

```bash
dotnet publish -o dist
```

上述命令等同於加上了 `-c Debug` 組態設定，是一樣意思：

```bash
dotnet publish -c Debug -o dist
```

> 注意: `-c Debug` 與 `-c DEBUG` 到最後都會轉大寫，你用 C# **條件式編譯**時，使用 `#if Debug` 是錯誤的寫法，用 `#if DEBUG` 才是正確的寫法！詳見 [C# 前置處理器指示詞](https://learn.microsoft.com/zh-tw/dotnet/csharp/language-reference/preprocessor-directives?WT.mc_id=DT-MVP-4015686) 文件。

其輸出路徑下的 `web.config` 內容長這樣：

```xml
<?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" />
    </system.webServer>
  </location>
</configuration>
```

這個設定檔，其實缺少了一組重要的「環境變數」名為 `ASPNETCORE_ENVIRONMENT`，而該環境變數的預設值為 `Production`，這個變數決定了 ASP․NET Core 跑在什麼樣的**環境**下，不同的環境可以註冊不同的 Middleware 與程式邏輯，因此學習到環境的切換技巧非常重要，本文稍後會特別強調如何調整環境定義。

除此之外，你也可以發行 `Release` 組態，而這兩種組態的差別，主要影響的範圍是 C# **條件式編譯**的結果！

```bash
dotnet publish -c Release -o dist
```

> 注意: `-c Release` 與 `-c RELEASE` 到最後都會轉大寫，你用 `#if Release` 是錯誤的寫法，用 `#if RELEASE` 才是正確的寫法！

### 發佈到測試環境（Development）

你可以在執行 `dotnet publish` 時，透過 `-p:EnvironmentName=Development` 明確指定「環境名稱」到發行的結果中：

```bash
dotnet publish -c Debug -p:EnvironmentName=Development
```

實際上會影響的地方，主要是輸出的 `web.config` 會自動內建環境變數的設定，非常方便！

```xml
<?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>
```

### 發佈到正式環境（Production）

相對的，你也可以在執行 `dotnet publish` 時，透過 `-p:EnvironmentName=Production` 明確指定 `Production` 這個「環境名稱」到發行的結果中：

```bash
dotnet publish -c Release -p:EnvironmentName=Production
```

以下是輸出的 `web.config` 內容，一樣內建包含了環境變數的設定！

```xml
<?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="Production" />
        </environmentVariables>
      </aspNetCore>
    </system.webServer>
  </location>
</configuration>
```

### 發佈時不要發佈 web.config 檔案

由於我們很有可能對 `web.config` 進行調整，下次在部署時可能會蓋掉 `web.config` 的內容，針對這個問題，你只要在執行 `dotnet publish` 時加上 `-p:IsTransformWebConfigDisabled=true` 參數，即可停用 `web.config` 輸出，發行目錄中就不會有 `web.config` 這個檔案存在！👍

```bash
dotnet publish -c Release -p:IsTransformWebConfigDisabled=true
```

### 發佈時不要發佈 web.config 檔案但必要時透過參數指定輸出

除此之外，你也可以直接在 `*.csproj` 加入一個 `IsTransformWebConfigDisabled` Property 並設定為 `true`，就可以變更預設的輸出不要包含 `web.config` 檔案，我個人比較喜歡這樣的設定方式：

```xml
<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net7.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <IsTransformWebConfigDisabled>true</IsTransformWebConfigDisabled>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.4" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
  </ItemGroup>

</Project>
```

之後你輸入 `dotnet publish -c Release` 預設就不會輸出 `web.config` 檔案：

```bash
dotnet publish -c Release
```

不過你依然可以從 CLI 設定 `-p:IsTransformWebConfigDisabled=false` 參數，讓該次發行輸出 `web.config` 檔案：

```bash
dotnet publish -c Release -p:IsTransformWebConfigDisabled=false
```

如果要連同輸出環境名稱，就可以這樣執行：

```bash
dotnet publish -c Release -p:IsTransformWebConfigDisabled=false -p:EnvironmentName=Production
```

### 相關連結

-   [.NET Core 多環境佈署設定 - iT 邦幫忙::一起幫忙解決難題，拯救 IT 人的一天](https://ithelp.ithome.com.tw/articles/10185314)
-   [c# - How to set ASPNETCORE\_ENVIRONMENT to be considered for publishing an ASP.NET Core application - Stack Overflow](https://stackoverflow.com/a/54432405/910074)
-   [C# preprocessor directives | Microsoft Learn](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/preprocessor-directives?WT.mc_id=DT-MVP-4015686#conditional-compilation)
