.Net Core 5 控制台应用程序,在 Program.Main 中完成时不会为环境加载应用程序设置

Posted

技术标签:

【中文标题】.Net Core 5 控制台应用程序,在 Program.Main 中完成时不会为环境加载应用程序设置【英文标题】:.Net Core 5 Console App, appsettings not loading for environment when done in Program.Main 【发布时间】:2021-12-24 02:22:59 【问题描述】:

我希望我的 .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");

这行得通;值“Staging”被加载到变量 _environment。

然后我将我的配置加载到一个静态变量中,如下所示:(编辑——这是我的错误,假设这个静态属性在静态 ctor 之后加载。实际上它在静态 ctor 之前加载。这意味着 _environment 变量不是set,这意味着我的环境特定的 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();

当我随后检查配置的内容时,我发现它只是从 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;",
  

但是当我从 Configuration 中读取 DataSource 时,它​​始终是“SqlDevelopment”,即使环境是 Staging。

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

    Microsoft.Extensions.Configuration Microsoft.Extensions.Configuration.Binder Microsoft.Extensions.Configuration.EnvironmentVariables Microsoft.Extensions.Configuration.Json

我错过了什么?

【问题讨论】:

【参考方案1】:

控制台应用程序检查 DOTNET_ 环境变量,而不是 ASPNETCORE_ 变量。这不是一个新的变化。它至少可以追溯到 .NET Core 3.1。您需要改为设置DOTNET_ENVIRONMENT

ASP.NET Core 应用程序使用除 DOTNET_ 变量之外的任何以 ASPNETCORE_ 为前缀的环境变量。

来自docs:

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

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

【讨论】:

这不起作用。我尝试过同时使用 ASPNETCORE_ENVIRONMENT 和 DOTNET_ENVIRONMENT。两者都不起作用。我还缺少其他东西。 你真的设置了环境变量吗?这些是操作系统或终端级别的设置,而不是launchsettings.json 中的行。该文件仅由 IDE 用于在启动进程时设置环境变量。当您在 IDE 之外运行应用程序时,不会使用该文件 至于I then load my Configuration into a static variable like so:为什么要这么做?这(几乎)是默认行为。 因为我需要访问我的 Program.Main 类中的配置。我正在使用launchSettings.json,因为我在调试器中运行应用程序。 @TomRegan 我已经解释过这是默认行为。当您使用Host.CreateDefaultBuilder(args) 时,默认行为是读取设置文件(包括环境文件)、环境变量命令行参数。【参考方案2】:

我需要在 Program.cs 的“Main”方法中访问我的配置,因此在该类中,我在静态构造函数中设置了一个模块级字符串变量“_environment”:

_environment = Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT");

这不是它的工作原理。您需要使用IHostEnvironment.EnvironmentName。如果您需要在 Main() 方法中访问您的配置,那么您做错了,读取环境变量是读取 (ASP).NET Core 环境名称的错误方式。

“(ASP).NET Core 环境名称”可以通过多种方式设置,一种方式是操作系统环境变量。但它们不是必须的,它们也可以通过命令行参数提供。

IHostEnvironment.EnvironmentName 是获取环境名称的正确方法。

【讨论】:

我的问题是,当我将两个 appsettings 文件显式加载到我的配置类中时,我做错了什么? Program.Main 中没有可用的 IHostEnvironment,但我从我的 launchSettings.json 显式获取环境名称并显式加载 appsettings.Staging.json。我在 .Net 核心 Web 应用程序中采用了完全相同的方法(在 Program.Main 中显式获取我的配置)并且它工作正常。 您的实际登台或生产部署不会有launchSettings.json(仅用于开发时间),所以这是您做错的第一件事。但是你是对的,如果你的代码通过.AddJsonFile($"appsettings._environment.json", ...) 并带有“Staging”的_environment 值,那么“appsettings.Staging.json”的内容应该覆盖“appsettings.json”的内容。如果不是,那么您实际上并没有部署 appsettings.Staging.json,或者您的文件名或值“ConnectionStrings”或“ConnectionStringName”中有错字。 我不担心部署,我只想在调试器中运行它,因此我从 launchSettings.json 获取环境名称。我没有得到覆盖,这就是问题所在。没有错字。 当然,您可以声称没有错字,但 Microsoft 配置扩展也没有损坏,否则它们将用于 很多 个项目。您有责任找出它为什么不起作用,并向我们提供足够的信息来帮助您解决问题。如果您将代码更改为仅.AddJsonFile($"appsettings._environment.json", optional: false) 会怎样?它运行吗?它可以找到文件吗?它可以解析它的内容吗?内容实际上是否包含您期望的键?显然,对于初学者来说,值“ConnectionStringName”在发布之前已被编辑。 谢谢!您设置 optional: false 的建议是我发现问题所需要的!不是打字错误,而是真正的拔毛者。我将在下面发布答案。【参考方案3】:

感谢大家,尤其是 @CodeCaster 对我的帮助。

问题是设置静态配置时 _environment 变量是空字符串。我假设因为我在静态构造函数中设置它是可用的,但是静态ctor实际上在运行之后我设置了我的静态配置,所以 _environment 是一个空字符串,所以“暂存”配置从未加载过。

我更改了代码,这样运行时就不会以我没想到的顺序设置变量:

    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 中。如果我不需要 Program.Main 中的配置,在调用 Host.CreateDefaultBuilder 之前,这些都不是必需的。

【讨论】:

您可以只使用 Host.CreateDefaultBuilder(args).Build(); 并获得相同的行为,以及日志记录和 DI 配置

以上是关于.Net Core 5 控制台应用程序,在 Program.Main 中完成时不会为环境加载应用程序设置的主要内容,如果未能解决你的问题,请参考以下文章

.Net Core 5 控制台应用程序,在 Program.Main 中完成时不会为环境加载应用程序设置

控制器无法识别 JWT 角色.net core 5

最全.NET Core .NET 5.NET 6和.NET 7简介和区别

Cosmos 的 .NET 5 和 Entity Framework Core (5.0.1) 迁移问题

.NET Core + React Antd Pro脚手架

[Asp.Net Core]NET5_Autofac控制器属性注入