1. 程式人生 > >深入理解.NET Core的基元(三) - 深入理解runtimeconfig.json

深入理解.NET Core的基元(三) - 深入理解runtimeconfig.json

原文:Deep-dive into .NET Core primitives, part 3: runtimeconfig.json in depth
作者:Nate McMaster
譯文:深入理解.NET Core的基元(三) - 深入runtimeconfig.json
譯者: Lamond Lu

前情回顧

  • 深入理解.NET Core的基元(一):deps.json, runtimeconfig.json, dll檔案
  • 深入理解.NET Core的基元(二):共享框架
  • 深入理解.NET Core的基元(三):深入理解runtimeconfig.json

簡介

每個.NET Core應用都包含了一個名為xxxx.runtimeconfig.json

的檔案。這個檔案可以用來控制多種配置。大多數的開發人員其實並不太關心這個檔案,因為它是由SDK生成的檔案,但是我認為它還是值得我們去學習理解一下的。這個檔案常用來控制一些不會在Visual Studio中表現出來的配置,例如在使用更高版本的.NET Core執行你的應用程式,調整執行緒池和垃圾回收等。

檔案的作用

從技術上講,runtimeconfig.json檔案並不是必須的,但是由於一些實踐性的因素,所以每個真實世界中的.NET Core應用都有持有一個runtimeconfig.json檔案。這個檔案是可以手動編輯的。與deps.json檔案不同,runtimeconfig.json是易於理解的。這個檔案的主要作用是定義程式所需的共享框架(只針對FDD - framework-dependency deployment

),以及一些其他的執行時選項,我會在後面一一列舉。

一個簡單的例子

以下是一個最典型的runtimeconfig.json的檔案內容。

{
  "runtimeOptions": {
    "tfm": "netcoreapp2.1",
    "framework": {
      "name": "Microsoft.NETCore.App",
      "version": "2.1.0"
    }
  }
}

我已經編寫了一個完整結構的runtimeconfig.json

檔案,如果有興趣你可以檢視<https://gist.github.com/natemcmaster/0bdee16450f8ec1823f2c11af880ceeb>。

runtimeconfig.template.json

在.NET Core中,有一些配置選項,你是不能在專案檔案.csproj中設定的。如果你想對這些配置選項進行設定,這裡有兩種方案,一種是在專案編譯之後,手動編輯runtimeconfig.json檔案,另外一種是使用runtimeconfig.template.json檔案。當然,如果你希望持久化配置, 我還是推薦你使用模板的方式。

當專案構建(build)的時候,SDK會從在.csproj檔案的基礎上,通過讀取模板擴充配置。下面我們就通過簡單的幾個步驟來使用模板。

  1. 建立一個新專案(dotnet new console -n MyApp

  2. 在當前專案目錄中,建立一個名為runtimeconfig.template.json的檔案。

  3. 配置檔案內容如下

    {
       "rollForwardOnNoCandidateFx": 2
    }
  4. 執行dotnet build

瞧,僅此而已。現在我們可以檢視一下bin/Debug/netacoreapp.21/MyApp.runtimeconfig.json,以確保模板正常工作。

Visual Studio的智慧感知

針對Visual Studio編輯器,我已經編寫了一個JSON結構,你可以直接使用。你需要做的,只是將如下程式碼加入到你當前專案的runtimeconfig.template.json檔案中即可。

{
  "$schema": "https://gist.githubusercontent.com/natemcmaster/0bdee16450f8ec1823f2c11af880ceeb/raw/runtimeconfig.template.schema.json"
}

執行時配置選項

框架、版本、先前滾動機制

.NET Core共享框架支援安裝並行版本,因此,當一個.NET Core應用程式啟動時候,必須選擇一個版本。以下配置選項常用於配置應用應該載入哪些共享框架,以及載入哪個版本的共享框架。

注意:通常來說SDK預設生成的配置就已經夠用了,但是有時候我們還是需要更改他們的,以解決.NET Core啟動時常見問題。

It was not possible to find any compatible framework version. The specified framework ‘Microsoft.NETCore.App’, version ‘X.Y.Z’ was not found.

共享框架

.NET Core是通過指定共享框架的名稱來指定共享框架的。配置中指定的框架版本,是當前應用使用的最低版本。如果你想不通過更改檔案覆蓋這個最小值配置,唯一的方式是使用dotnet exec --fx-version命令。

在.NET Core 3.0以下版本中,一次只能指定一個共享框架。

JSON

{
  "runtimeOptions": {
    "framework": {
      "name": "Microsoft.AspNetCore.App",
      "version": "2.2.0"
    }
  }
}

.csproj

<ItemGroup>
  <PackageReference Include="Microsoft.AspNetCore.App" Version="2.2.0" />
</ItemGroup>

對於.NET Core 3.0及以上版本中已經支援多共享框架,所以額外的共享框架不再需要作為包來引用了。

JSON

{
  "runtimeOptions": {
    "frameworks": [
      {
        "name": "Microsoft.AspNetCore.App",
        "version": "3.0.0"
      },
      {
        "name": "Microsoft.WindowsDesktop.App",
        "version": "3.0.0"
      }
    ]
  }
}

.csproj

<ItemGroup>
  <FrameworkReference Include="Microsoft.AspNetCore.App" />
  <FrameworkReference Include="Microsoft.WindowsDesktop.App" />
</ItemGroup>

自動使用更高版本.NET Core執行程式

這個是.NET Core 3.0中的一個新配置選項。

預設,.NET Core會去嘗試尋找當前共享框架的,最高修補版本。如果找不到這個版本,它會使用前滾(roll-forward)特性,來查詢較新的版本。這個選項受前滾策略的控制。

JSON

{
  "runtimeOptions": {
    "rollForward": "Major"
  }
}

.csproj

當前.csproj專案檔案中還沒有實現這個配置。

你可以在https://github.com/dotnet/designs/blob/master/accepted/runtime-binding.md中找到這個配置的規範。針對這個配置,官方設計文件中,做了如下描述

RollForward引數有一下幾個可選值:

  • LatestPatch - 前滾到最高修補版本,這個配置會禁用前滾特性的最小版本配置。
  • Minor - 如果缺少所需的次要版本,就前滾到最低的次要版本。如果請求的次要版本存在,則使用LatestPatch策略
  • Major - 如果缺少所需的主要版本,則前滾到最低的主要版本,和最低的次要版本。如果請求的主要版本存在,則使用Minor策略
  • LatestMinor - 前滾到最高次要版本,即使當前請求的次要版本存在
  • LatestMajor - 前滾到最高主要版本和最高次要版本,即使當前請求的主要版本存在
  • Disable - 不適用前滾特性。只繫結指定版本。在大多數場景下,這個策略都是不推薦的,因為它會禁用前滾到最新修補版本的能力。這種方式僅推薦來做測試工作。

Minor是當前配置的預設值。如果希望瞭解更多資訊,可以參閱官方文件。

在以上配置值中,除了Disable選項之外,其他的選項都是會去選擇最高的可用修補版本。

注意: LatestMinorLatestMajor適用於託管和非託管中主機的元件託管(例如託管COM元件)

自動使用更高的補丁版本執行專案(.NET Core 3.0之前的版本)

正如上面所描述的,在.NET Core 3.0中不推薦使用此策略,而推薦使用更簡單的"前滾"選項。

預設情況下,.NET Core會使用安裝在目標機器中最高修補版本的共享框架執行程式。你可以使用applyPatches引數禁用此功能。

JSON

{
  "runtimeOptions": {
    "applyPatches": false
  }
}

.csproj

當前.csproj專案檔案中還沒有實現這個配置。

自動使用最高主版本或次要版本來執行專案(.NET Core 3.0之前的版本)

正如上面所描述的,在.NET Core 3.0中不推薦使用此策略,而推薦使用更簡單的"前滾"選項。

預設情況下,.NET Core會嘗試自動查詢共享框架的最高補丁版本,該版本的主版本和次要版本和你當前執行的應用所指定的版本相同。但是,如果找不到,它會自動前滾到最新版本。此配置受前滾策略控制。

JSON

{
  "runtimeOptions": {
    "rollForwardOnNoCandidateFx": 1
  }
}

.csproj

當前.csproj專案檔案中還沒有實現這個配置。

這個引數的值,可以設定為0,1,2。你可以檢視詳細的設計文件,瞭解更多詳情。

例如,當指定的框架版本是2.1.0時,.NET Core會根據這個引數的值,決定使用如下的相容框架版本。

rollForwardOnNoCandidateFx 相容的框架版本
0 >=2.1.0, < 2.2.0
1 (預設) >=2.1.0, < 3.0.0
2 >=2.1.0

目標框架名稱

這是一個執行時程式包儲存的實現細節。

JSON

{
  "runtimeOptions": {
    "tfm": "netcoreapp2.1"
  }
}

.csproj

<PropertyGroup>
  <TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>

程式集探測路徑

宿主程式可以使用這個引數來指定額外的資料夾,以查詢.deps.json檔案中列舉的程式集檔案。你可以檢視系列文章的第一篇來檢視這個引數是如何工作的。

JSON

{
  "runtimeOptions": {
    "additionalProbingPaths": [
      "C:\\Users\\nmcmaster\\.nuget\\packages\\"
    ]
  }
}

.csproj

<ItemGroup>
  <AdditionalProbingPath Include="$(USERPROFILE)\.nuget\packages" />
</ItemGroup>

注意:.csproj中的配置項最終只會出現在runtimeconfig.dev.json檔案中,該檔案僅在開發過程中使用,而不會在生產環境中使用。針對生產環境,你可以使用模板檔案來設定runtimeconfig.json

執行時配置

configProperties屬性是提供給執行時的鍵/值對列表。基本上你能想到的配置,在這裡都設定,但是最常使用的配置一般是如下幾個。

JSON

{
  "runtimeOptions": {
    "configProperties": {
      "key": "value"
    }
  }
}

常用的執行時配置

配置名稱 型別 描述
System.GC.Server 布林 是否啟用伺服器垃圾回收
System.GC.Concurrent 布林 是否啟用併發垃圾回收
System.GC.RetainVM 布林 是否將應刪除的段放入一個備用列表中以備將來使用,而不是將其釋放回作業系統。
System.Runtime.TieredCompilation 布林 是否啟用分層編譯
System.Threading.ThreadPool.MinThreads 整型 覆蓋執行緒池的最小執行緒數
System.Threading.ThreadPool.MaxThreads 整型 覆蓋執行緒池的最大執行緒數
System.Globalization.Invariant 布林 是否啟用不變模式,禁用全球化行為

以下是一些針對上述配置的文件說明

  • 主機配置開關(Host Configuration Knobs)
  • 全球化不變模式
  • 分層編譯

這些配置,你都可以放在你的.csproj檔案中。如果你想了解更多相關配置,最好的方案就是去檢視Microsoft.NET.Sdk.targets檔案。

<PropertyGroup>
  <ConcurrentGarbageCollection>true</ConcurrentGarbageCollection>
  <ServerGarbageCollection>true</ServerGarbageCollection>
  <RetainVMGarbageCollection>true</RetainVMGarbageCollection>
  <ThreadPoolMinThreads>1</ThreadPoolMinThreads>
  <ThreadPoolMaxThreads>100</ThreadPoolMaxThreads>
  <!-- Supported as of .NET Core SDK 3.0 Preview 1 -->
  <TieredCompilation>true</TieredCompilation>
  <InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>

其他執行時配置

除了框架提供的配置,.NET Core還允許開發人員指定自己的配置。你可以通過System.AppContext.GetData方法來獲取這些值。

注意:相較於配置構建器(Configuration Builders), 這個方式並不是特別推薦。

JSON

{
  "runtimeOptions": {
    "configProperties": {
      "ArbitraryNumberSetting": 2,
      "ArbitraryStringSetting": "red",
      "ArbitraryBoolSetting": true
    }
  }
}

.csproj

<ItemGroup>
  <RuntimeHostConfigurationOption Include="ArbitraryNumberSetting" Value="2" />
  <RuntimeHostConfigurationOption Include="ArbitraryStringSetting" Value="red" />
  <RuntimeHostConfigurationOption Include="ArbitraryBoolSetting" Value="true" />
</ItemGroup>

在C#中,通過System.AppContext.GetData方法來獲取指定引數的值

// "red"
var color = System.AppContext.GetData("ArbitraryStringSetting") as string;

更多資訊

你可以通過檢視本系列的第一章來了解runtimeconfig.json檔案的更多詳情,以及如何使用它。同樣,我也推薦你通過官方的文件檔案來了解一下這些變數配置是如何使用的。