.Net Core 5控制台应用程序,当在Program.Main中完成时,appsettings无法加载特定环境的设置。

7
我希望我的 .Net Core 5 控制台应用程序能够根据 DOTNET_ENVIRONMENT 环境变量从适当的 appsettings 文件中选择设置。我在 Visual Studio 2019 调试器中运行代码,并从 launchSettings.json 文件中获取环境测试。
在 .Net Core 5 控制台应用程序中,我有 4 个 "appsettings" 文件:
- appsettings.json - appsettings.Development.json - appsettings.Staging.json - appsettings.Production.json
每个文件的属性都设置为 Build Action:Content,并且 Copy to Output Directory:Copy if newer。
在 launchSettings.json 中,我将环境设置为 "Staging",如下所示:
 {
  "profiles": {
    "MyAppName": {
      "commandName": "Project",
      "dotnetRunMessages": "true",
      "environmentVariables": {
        "DOTNET_ENVIRONMENT": "Staging"
      }
    }
  }
}

我需要在Program.cs的"Main"方法中访问我的配置信息,所以在那个类中,我通过静态构造方法设置了一个模块级别的字符串变量"_environment",代码如下:

_environment = Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT");

这个代码是有效的,变量_environment加载了值"Staging"。

然后我像这样将我的配置加载到静态变量中:(编辑-这是我的错误,我假设这个静态属性在静态构造函数之后加载。实际上,它在静态构造函数之前加载。这意味着_environment变量没有设置,这意味着我的环境特定的appsettings文件永远不会加载)。

private static IConfiguration Configuration { get; } = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
    .AddJsonFile($"appsettings.{_environment}.json", optional: true, reloadOnChange: true)
    .AddEnvironmentVariables()
    .Build();

当我检查Configuration的内容时,我发现它只从appsettings.json中加载值。它没有从appsettings.Staging.json加载值。 我要查找的特定值是“ConnectionStrings”。这是appsettings.json中ConnectionStrings部分的样子:
"ConnectionStrings": {
    "ConnectionStringName": "Data Source=SqlDevelopment; Initial Catalog=MyTable; Integrated Security=SSPI;",
  }

下面是相同部分在appsettings.Staging.json文件中的样子:

"ConnectionStrings": {
    "ConnectionStringName": "Data Source=SqlStaging; Initial Catalog=MyTable; Integrated Security=SSPI;",
  }

但是当我从配置中读取DataSource时,它总是 "SqlDevelopment",即使环境是Staging。

尝试并失败后,我尝试加载这4个NuGet包,但没有效果:

  1. Microsoft.Extensions.Configuration
  2. Microsoft.Extensions.Configuration.Binder
  3. Microsoft.Extensions.Configuration.EnvironmentVariables
  4. Microsoft.Extensions.Configuration.Json

我错过了什么?

3个回答

7
控制台应用程序检查 DOTNET_ 环境变量,而不是 ASPNETCORE_ 变量。这并不是一个新的改变,它至少可以追溯到.NET Core 3.1。您需要设置 DOTNET_ENVIRONMENT
ASP.NET Core应用程序使用以 ASPNETCORE_ 为前缀的任何环境变量,除了 DOTNET_ 变量之外。
文档中可以得知:
引用:

默认配置加载以DOTNET_和ASPNETCORE_为前缀的环境变量和命令行参数。DOTNET_和ASPNETCORE_前缀由ASP.NET Core用于主机和应用程序配置,但不用于用户配置。有关主机和应用程序配置的详细信息,请参阅.NET通用承载。

PS:就在10分钟前,我遇到了同样的问题,并意识到我设置了DOTNETCORE_ENVIRONMENT而不是 DOTNET_ENVIRONMENT

2
这个不起作用。我已经尝试使用ASPNETCORE_ENVIRONMENT和DOTNET_ENVIRONMENT两种方式,但都没有成功。我还缺少其他东西。 - Tom Regan
你是否真正设置了环境变量?这些是操作系统或终端级别的设置,而不是launchsettings.json文件中的行。该文件仅在IDE启动进程时用于设置环境变量。当您在IDE之外运行应用程序时,该文件不会被使用。 - Panagiotis Kanavos
关于“然后我将我的配置加载到静态变量中,就像这样:”,为什么要那样做?那(几乎)是默认行为。 - Panagiotis Kanavos
因为我需要在我的Program.Main类中访问Configuration。而且我正在使用launchSettings.json,因为我正在调试应用程序。 - Tom Regan
@TomRegan 我已经解释过这是默认行为。当你使用 Host.CreateDefaultBuilder(args) 时,默认行为是读取设置文件(包括环境文件)、环境变量和命令行参数。 - Panagiotis Kanavos
我的代码和方法都没问题,除了我从launchSettings.json设置_environment字符串变量的位置。一旦我将其移动到静态构造函数中,它就正常工作了。 - Tom Regan

2

I need access to my configuration in the "Main" method in Program.cs, so in that class I am setting a module-level string variable "_environment" like so in the static constructor:

_environment = Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT");
这不是正确的操作方式。您需要使用IHostEnvironment.EnvironmentName。如果您需要在Main()方法中访问配置,则可能出了一些问题,读取环境变量是获取(ASP).NET Core环境名称的错误方式。
"(ASP).NET Core环境名称"可通过多种方式设置,其中之一是操作系统环境变量。但这不是必须的,也可以通过命令行参数提供。 IHostEnvironment.EnvironmentName是获取环境名称的正确方法。

我的问题是,当我将两个appsettings文件显式加载到我的Configuration类中时,我做错了什么?在Program.Main中没有可用的IHostEnvironment,但我从我的launchSettings.json中明确获取环境名称并明确加载appsettings.Staging.json。我在一个.Net Core Web应用程序中遵循了完全相同的方法(在Program.Main中明确获取我的配置),它可以正常工作。 - Tom Regan
1
你的实际暂存或生产部署不会有launchSettings.json(那只是用于开发时间),所以这是你做错的第一件事。但你是对的,如果你的代码通过.AddJsonFile($"appsettings.{_environment}.json", ...)并且_environment值为“Staging”,那么“appsettings.Staging.json”的内容应该覆盖“appsettings.json”的内容。如果没有,那么你实际上没有部署appsettings.Staging.json,或者你的文件名或“ConnectionStrings”或“ConnectionStringName”的值中有拼写错误。 - CodeCaster
我不担心部署,我只想在调试器中运行它,因此我从launchSettings.json中获取环境名称。我没有得到覆盖,这就是问题所在。没有打字错误。 - Tom Regan
1
当然,你可以声称没有错别字,但是微软配置扩展也没有出现问题,否则将会有很多项目出现问题。你需要自己找出为什么它不起作用,并提供足够的信息来帮助你找出原因。如果你将代码更改为.AddJsonFile($"appsettings.{_environment}.json", optional: false),会发生什么?它能运行吗?它能找到文件吗?它能解析文件内容吗?文件内容实际上包含了你期望的键吗?显然,“ConnectionStringName”这个值在发布之前已经被编辑过了。 - CodeCaster
1
谢谢!您建议将optional: false设置为必需,这正是我需要找到问题的方法!这不是笔误,而是一个真正的难题。我会在下面发布答案。 - Tom Regan

1

谢谢大家,特别是 @CodeCaster 帮了我。

问题在于当静态 Configuration 被设置时,_environment 变量为空字符串。我认为因为我在静态构造函数中设置它,所以它是可用的,但实际上静态构造函数运行 在我设置静态 Configuration 后,所以 _environment 是一个空字符串,因此“Staging”配置从未被加载。

我修改了代码,这样就不会有可能运行时按我没有预期的顺序设置变量:

    private static IConfiguration Configuration { get; } = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
        .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT")}.json", optional: true, reloadOnChange: true)
        .Build();

一些海报基本上告诉我“你做错了。” 我意识到运行时在调用Host.CreateDefaultBuilder()之后提供了一个依赖注入的配置。由于问题范围之外的原因,我碰巧需要在Program.Main内部在该调用发生之前获取Configuration。如果我不需要在Host.CreateDefaultBuilder之前在Program.Main中使用Configuration,则所有这些都是不必要的。

你可以使用 Host.CreateDefaultBuilder(args).Build(); 来获得相同的行为,同时也包括日志记录和 DI 配置。 - Panagiotis Kanavos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接