﻿# 使用 global.json 精準的選擇 .NET SDK 版本

我在 2018 年寫過一篇 [如何在多個 .NET Core SDK 版本之間進行切換 (global.json)](/post/2018/04/19/How-to-switch-between-DotNet-SDK-versions) 文章，當時只說明了你如何選擇特定版本，沒有提到當有新版 .NET SDK 出現時，他會怎樣選擇版本。這篇文章我打算來補完這部分技術細節。

### 前情提要

首先，各位先看看我目前電腦的 .NET SDK 安裝情況，我從 .NET Core 3.1 到 .NET 6 Preview 都有安裝：

```batch
C:\NETSDK>dotnet --version
6.0.100-preview.4.21255.9

C:\NETSDK>dotnet --list-sdks
3.1.100 [C:\Program Files\dotnet\sdk]
3.1.115 [C:\Program Files\dotnet\sdk]
3.1.201 [C:\Program Files\dotnet\sdk]
3.1.301 [C:\Program Files\dotnet\sdk]
3.1.302 [C:\Program Files\dotnet\sdk]
3.1.402 [C:\Program Files\dotnet\sdk]
3.1.409 [C:\Program Files\dotnet\sdk]
5.0.104 [C:\Program Files\dotnet\sdk]
5.0.203 [C:\Program Files\dotnet\sdk]
5.0.300 [C:\Program Files\dotnet\sdk]
6.0.100-preview.4.21255.9 [C:\Program Files\dotnet\sdk]
```

> 在沒有 `global.json` 檔案的情況下，預設 .NET SDK 只會選擇目前的最新版本。

事實上，專案團隊中的每個人安裝的 .NET SDK 版本不盡相同，例如有的人安裝了 `5.0.202` 版，由些人則安裝了 `5.0.203` 版，那麼我們的 `global.json` 應該設定哪個版本才好呢？答案是：**設定主要版本的第一版！** 例如：`3.1.100` 或 `5.0.100` 等等。

假設我就在我的電腦執行以下命令，建立 `global.json` 檔案：

```bash
dotnet new globaljson --sdk-version 5.0.100
```

```json
{
  "sdk": {
    "version": "5.0.100"
  }
}
```

由於我的電腦並沒有 `5.0.100` 版本，所以當我執行 `dotnet --version` 我會得到 `5.0.104` 這個版本：

```batch
G:\NETSDK>dotnet new globaljson --sdk-version 5.0.100
The template "global.json file" was created successfully.

G:\NETSDK>type global.json
{
  "sdk": {
    "version": "5.0.100"
  }
}
G:\NETSDK>dotnet --version
5.0.104
```

這也意味著著：【**當 .NET SDK 無法透過 `global.json` 找到相對應版本時，它會自動找出往後最新的主要 SDK 版本**】

> 如果你設定的 .NET SDK 版本在開發者的電腦有安裝的話，就會直接選擇特定版本。

### 認識 .NET SDK 的版本定義

我以 `3.1.115` 版本為例，這個版號可以區分成以下幾種：

1.  主要版本 (**Major**)
    
    ```log
    3
    ```
    
    > 版號第一段的數字。
    
2.  次要版本 (**Minor**)
    
    ```log
    1
    ```
    
    > 版號第二段的數字。
    
3.  功能版本 (**Feature**)
    
    ```log
    1
    ```
    
    > 版號第三段的第一個數字。
    
4.  修補版本 (**Patch**)
    
    ```log
    15
    ```
    
    > 版號第三段的最後兩個數字。
    

### 如何更佳精準的控制 .NET SDK 選用版本

為了能夠更精準的控制版本的跳躍，以下我用 .NET Core 3.1 來當示範整個步驟。

1.  建立 `global.json` 選用 .NET Core SDK `3.1.100` 版本
    
    ```bash
    dotnet new globaljson --sdk-version 3.1.100
    ```
    
    ```json
    {
      "sdk": {
        "version": "3.1.100"
      }
    }
    ```
    
    因為我的電腦正好有安裝 `3.1.100` 這個 .NET SDK 版本，此時你用 `dotnet --version` 會得到 `3.1.100` 版本！
    
2.  我們將 `global.json` 加入 `sdk.rollForward` 屬性，並設定為 `latestPatch`
    
    ```json
    {
      "sdk": {
        "version": "3.1.100",
        "rollForward": "latestPatch"
      }
    }
    ```
    
    此時你會發現，因為定義 `sdk.rollForward` 屬性為 `latestPatch` 的關係，我們用 `dotnet --version` 會得到 `3.1.115` 版本！
    
3.  我們將 `global.json` 的 `sdk.rollForward` 屬性修改為 `latestFeature`
    
    ```json
    {
      "sdk": {
        "version": "3.1.100",
        "rollForward": "latestFeature"
      }
    }
    ```
    
    此時你會發現，因為定義 `sdk.rollForward` 屬性為 `latestFeature` 的關係，我們用 `dotnet --version` 會得到 `3.1.409` 版本！
    
4.  我們將 `global.json` 的 `sdk.rollForward` 屬性修改為 `latestMinor`
    
    ```json
    {
      "sdk": {
        "version": "3.1.100",
        "rollForward": "latestMinor"
      }
    }
    ```
    
    因為我們並沒有 `3.2` 版可用，定義 `sdk.rollForward` 屬性為 `latestMinor` 將會與 `latestFeature` 的結果一模一樣，我們用 `dotnet --version` 會得到 `3.1.409` 版本！
    
5.  我們將 `global.json` 的 `sdk.rollForward` 屬性修改為 `latestMajor`
    
    ```json
    {
      "sdk": {
        "version": "3.1.100",
        "rollForward": "latestMajor"
      }
    }
    ```
    
    因為定義 `sdk.rollForward` 屬性為 `latestMajor` 的關係，我們用 `dotnet --version` 會得到 `6.0.100-preview.4.21255.9` 版本！
    
    請注意！上述設定直接讓 .NET SDK 跳到**最新預覽版**了，如果你只希望套用到**最新穩定版**的話，可以調整設定如下：
    
    ```json
    {
      "sdk": {
        "version": "3.1.100",
        "rollForward": "latestMajor",
        "allowPrerelease": false
      }
    }
    ```
    
    > 這個也是我最喜歡的 `globaljson` 設定值！
    
6.  我們將 `global.json` 的 `sdk.rollForward` 屬性修改為 `disable`
    
    ```json
    {
      "sdk": {
        "version": "3.1.100",
        "rollForward": "disable"
      }
    }
    ```
    
    因為定義 `sdk.rollForward` 屬性為 `disable` 的關係，我們用 `dotnet --version` 會得到 `3.1.100` 版本！
    
    > 注意：使用 `disable` 設定後，如果開發人員沒有安裝確切的指定版本， 完全無法使用 .NET SDK 了！
    

以上這幾個就很夠用了，其他的就沒有很重要。

### 使用 `*` (萬用字元) 標示版本

如果你在 `global.json` 使用 `*` (萬用字元) 標示版本的話，如下：

```json
{
  "sdk": {
    "version": "3.1.*",
    "rollForward": "latestMajor",
    "allowPrerelease": false
  }
}
```

不管你設定什麼版本，任何**無效的版本**對 .NET SDK 來說，就等同於這份 `global.json` 不存在一樣。只要這份 `global.json` 的 JSON 格式正確，基本上 .NET SDK 執行的時候就不會報錯，所以你寫這樣也是會過的：

```json
{
  "sdk": {
    "version": "3.1.100",
    "rollForward": "latestWhatever",
    "allowPrerelease": false
  }
}
```

既然都視為不存在，.NET SDK 就會自動選擇目前的最新主要、次要、功能、修補版本，反正是最新版就對了！

所以上述的兩種**錯誤設定**，由於執行 .NET SDK 的工具時都不會報錯，所以很有可能會讓你**覺得**這是**應該是**正確的設定，各位要千萬小心，不要自己腦補邏輯進去。

你可以用 `dotnet --version` 測試看看，錯誤的設定將會得到 `6.0.100-preview.4.21255.9` 版本！ 🔥

### 相關連結

-   [Select the .NET version to use](https://learn.microsoft.com/en-us/dotnet/core/versions/selection?WT.mc_id=DT-MVP-4015686)
-   [global.json overview - .NET CLI | Microsoft Docs](https://learn.microsoft.com/en-us/dotnet/core/tools/global-json?tabs=netcore3x&WT.mc_id=DT-MVP-4015686)
-   [Understanding ASP.NET Core Patch Version Roll Forward - Stack Overflow](https://stackoverflow.com/a/56984332/910074)
