原文:Deep-dive into .NET Core primitives, part 3: runtimeconfig.json in depth

作者:Nate McMaster

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

译者: Lamond Lu

前情回顾

简介

每个.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 布尔 是否启用不变模式,禁用全球化行为

以下是一些针对上述配置的文档说明

这些配置,你都可以放在你的.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文件的更多详情,以及如何使用它。同样,我也推荐你通过官方的文档文件来了解一下这些变量配置是如何使用的。

深入理解.NET Core的基元(三) - 深入理解runtimeconfig.json的更多相关文章

  1. 深入理解.NET Core的基元(二) - 共享框架

    原文:Deep-dive into .NET Core primitives, part 2: the shared framework 作者:Nate McMaster 译文:深入理解.NET Co ...

  2. 深入理解.NET Core的基元(二)

    原文:Deep-dive into .NET Core primitives, part 2: the shared framework作者:Nate McMaster译文:深入理解.NET Core ...

  3. 深入理解.NET Core的基元: deps.json, runtimeconfig.json, dll文件

    原文链接: Deep-dive into .NET Core primitives: deps.json, runtimeconfig.json, and dll's 作者: Nate McMaste ...

  4. CLR via C#深解笔记三 - 基元类型、引用类型和值类型 | 类型和成员基础 | 常量和字段

    编程语言的基元类型   某些数据类型如此常用,以至于许多编译器允许代码以简化的语法来操纵它们. System.Int32 a = new System.Int32();  // a = 0 a = 1 ...

  5. 深入理解net core中的依赖注入、Singleton、Scoped、Transient(三)

    相关文章: 深入理解net core中的依赖注入.Singleton.Scoped.Transient(一) 深入理解net core中的依赖注入.Singleton.Scoped.Transient ...

  6. CLR via #C读书笔记三:基元类型、引用类型和值类型

    1.一些开发人员说应用程序在32位操作系统上运行,int代表32位整数:在64位操作系统上运行,int代表64位整数.这个说法是完全错误的.C#的int始终映射到System.Int32,所以不管在什 ...

  7. 读经典——《CLR via C#》(Jeffrey Richter著) 笔记_基元类型(三)

    [checked 和 unchecked 基元类型操作] 1.第一种使用方式 UInt32 invalid = )); //OK,不会抛异常 Byte b = ; b = ));//抛出Overflo ...

  8. 【C#进阶系列】28 基元线程同步构造

    多个线程同时访问共享数据时,线程同步能防止数据损坏.之所以要强调同时,是因为线程同步问题实际上就是计时问题. 不需要线程同步是最理想的情况,因为线程同步一般很繁琐,涉及到线程同步锁的获取和释放,容易遗 ...

  9. 谈谈C#基元类型

    首先看一下.NET 中的基元类型,如下表: C# Type | .NET Framework Type -------------| ---------------------- bool | Sys ...

随机推荐

  1. ARM、X86和AI处理器的区别

    ARM.X86和AI处理器的区别 目前主要的处理器架构有: X86: Intel, AMD, 海光, 兆芯 ARM: 华为,飞腾,华芯通,Cavium,Ampere,富士通,亚马逊 POWER:IBM ...

  2. go map数据结构和源码详解

    目录 1. 前言 2. go map的数据结构 2.1 核心结体体 2.2 数据结构图 3. go map的常用操作 3.1 创建 3.2 插入或更新 3.3 删除 3.4 查找 3.5 range迭 ...

  3. JAVA基础知识注意事项

    JAVA核心技术卷一 (第十版) 下面是需要注意的: 只有方法名和参数类型叫做方法的签名, 不同的返回类型值不能作为方法的签名.(4.6.1) 这是域与局部变量的主要不同点. 必须明确地初始化方法中的 ...

  4. oop面向对象知识总结 静态成员和友元

    第十一章 静态成员和友元 11.1 静态成员 1.C++类当中的静态数据成员仍借用保留字static,但是与之前的静态全局变量,静态局部变量以及静态函数没有关系. 2.静态数据成员不占用具体对象的数据 ...

  5. [springboot 开发单体web shop] 5. 用户登录及首页展示

    用户登录及前端展示 用户登录 在之前的文章中我们实现了用户注册和验证功能,接下来我们继续实现它的登录,以及登录成功之后要在页面上显示的信息. 接下来,我们来编写代码. 实现service 在com.l ...

  6. 如何在SqlServer中使用层级节点类型hierarchyid

    Sql Server2008开始新增的 hierarchyid 数据类型使存储和查询层次结构数据变得更为简单. 为了使用这个类型,笔者在此进行简单记录,同时为需要的朋友提供一个简单的参考. --获取层 ...

  7. 零基础Linux入门之《Linux就该这么学》

    本书是由全国多名红帽架构师(RHCA)基于最新Linux系统共同编写的高质量Linux技术自学教程,极其适合用于Linux技术入门教程或讲课辅助教材,目前是国内最值得去读的Linux教材,也是最有价值 ...

  8. inux下vi命令大全

    分类: LINUX 进入vi的命令 vi filename :打开或新建文件,并将光标置于第一行首 vi +n filename :打开文件,并将光标置于第n行首 vi + filename :打开文 ...

  9. node.js 需要注意知识点

    复习node.js 需要注意知识点--(重点) 2.1:参数传递获取造型 客户端脚手架(发)    (参数传递)    node.js(收) -发ajax  this.axios.get(" ...

  10. .NET单例模式快速学习应用

    单例模式属于设计模式中最简单的一个模式,在实际应用中也非常广泛,但可能是受到各类教程的影响,看到很多实现方式仍然沿用Java的那一套,其实在.NET中可以用更简洁的实现方式. 一.知识点介绍 核心目标 ...