深入理解.NET Core的基元(三) - 深入理解runtimeconfig.json
原文:Deep-dive into .NET Core primitives, part 3: runtimeconfig.json in depth
作者:Nate McMaster[1]
譯文:深入理解.NET Core 的基元(三) - 深入 runtimeconfig.json
作者:Lamond Lu
前情回顧
深入理解.NET Core 的基元(一):deps.json, runtimeconfig.json, dll 文件[2]
深入理解.NET Core 的基元(二):共享框架[3]
簡介
每個.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文件,如果有興趣你可以查看[5]。
runtimeconfig.template.json
在.NET Core 中,有一些配置選項,你是不能在項目文件.csproj中設置的。如果你想對這些配置選項進行設置,這里有兩種方案,一種是在項目編譯之后,手動編輯runtimeconfig.json文件,另外一種是使用runtimeconfig.template.json文件。當然,如果你希望持久化配置, 我還是推薦你使用模板的方式。
當項目構建(build)的時候,SDK 會從在.csproj文件的基礎上,通過讀取模板擴充配置。下面我們就通過簡單的幾個步驟來使用模板。
創建一個新項目(dotnet new console -n MyApp)
在當前項目目錄中,創建一個名為runtimeconfig.template.json的文件。
配置文件內容如下
{"rollForwardOnNoCandidateFx": 2
}
執行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[6]中找到這個配置的規范。針對這個配置,官方設計文檔中,做了如下描述
RollForward參數有以下幾個可選值:
LatestPatch - 前滾到最高修補版本,這個配置會禁用前滾特性的最小版本配置。
Minor - 如果缺少所需的次要版本,就前滾到最低的次要版本。如果請求的次要版本存在,則使用LatestPatch策略
Major - 如果缺少所需的主要版本,則前滾到最低的主要版本,和最低的次要版本。如果請求的主要版本存在,則使用Minor策略
LatestMinor - 前滾到最高次要版本,即使當前請求的次要版本存在
LatestMajor - 前滾到最高主要版本和最高次要版本,即使當前請求的主要版本存在
Disable - 不適用前滾特性。只綁定指定版本。在大多數場景下,這個策略都是不推薦的,因為它會禁用前滾到最新修補版本的能力。這種方式僅推薦來做測試工作。
Minor是當前配置的默認值。如果希望了解更多信息,可以參閱官方文檔[7]。
在以上配置值中,除了Disable選項之外,其他的選項都是會去選擇最高的可用修補版本。
注意:LatestMinor和LatestMajor適用于托管和非托管中主機的組件托管(例如托管 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。你可以查看詳細的設計文檔[8],了解更多詳情。
例如,當指定的框架版本是 2.1.0 時,.NET Core 會根據這個參數的值,決定使用如下的兼容框架版本。
| 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文件中列舉的程序集文件。你可以查看系列文章的第一篇[9]來查看這個參數是如何工作的。
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)[10]
全球化不變模式[11]
分層編譯[12]
這些配置,你都可以放在你的.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;
更多信息
你可以通過查看本系列的第一章[13]來了解runtimeconfig.json文件的更多詳情,以及如何使用它。同樣,我也推薦你通過官方的文檔文件[14]來了解一下這些變量配置是如何使用的。
參考資料
[1]
Nate McMaster: https://natemcmaster.com/
[5]https://gist.github.com/natemcmaster/0bdee16450f8ec1823f2c11af880ceeb: https://gist.github.com/natemcmaster/0bdee16450f8ec1823f2c11af880ceeb
[6]https://github.com/dotnet/designs/blob/master/accepted/runtime-binding.md: https://github.com/dotnet/designs/blob/master/accepted/runtime-binding.md
[7]官方文檔: https://github.com/dotnet/designs/blob/master/accepted/runtime-binding.md#configuration-precedence
[8]設計文檔: https://github.com/dotnet/core-setup/blob/92072fd9ea03740ea317b631d3894ff3c5d0854d/Documentation/design-docs/roll-forward-on-no-candidate-fx.md
[10]主機配置開關(Host Configuration Knobs): https://github.com/dotnet/coreclr/blob/v2.2.0/Documentation/project-docs/clr-configuration-knobs.md
[11]全球化不變模式: https://github.com/dotnet/corefx/blob/v2.2.0/Documentation/architecture/globalization-invariant-mode.md
[12]分層編譯: https://blogs.msdn.microsoft.com/dotnet/2018/08/02/tiered-compilation-preview-in-net-core-2-1/
[14]文檔文件: https://github.com/dotnet
總結
以上是生活随笔為你收集整理的深入理解.NET Core的基元(三) - 深入理解runtimeconfig.json的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Hyper-V虚拟机自动添加检查点和导出
- 下一篇: 微软正在开发基于Rust的安全编程语言