.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 中完成时不会为环境加载应用程序设置
最全.NET Core .NET 5.NET 6和.NET 7简介和区别