在自托管 .net core 2.2 应用程序上正确使用 IsDevelopement()

Proper use of IsDevelopement() on self hosted .net core 2.2 application

我有一个自托管的 .NET Core 2.2 控制台应用程序,它不使用 Web 主机构建器,因为我不需要此服务的 HTTP 端点。

我正在尝试通过托管环境的 IsDevelopment() 方法利用环境变量,但它总是以 Production 的形式返回。

以下是我设置主机生成器的方式。我有一个名为 ASPNETCORE_ENVIRONMENT 的环境变量,其值为 Development,这让我问了两个问题。

  1. 构建我自己的主机时设置此设置的正确方法是什么,以便我可以在构建主机时有条件地将用户机密添加到我的配置中?
  2. 第二个问题是我是否可以使用 ASPNETCORE_ENVIRONMENT 以外的其他环境变量,因为我的应用程序不是 ASP.NET 核心应用程序?

我意识到我可能会在构建明确查找环境变量并手动设置环境的 HostBuilder 之前编写代码,但是 ASP.NET Core 似乎在幕后将其连接起来所以我想看看是否有办法在我不使用网络主机构建器时获得类似的行为。

private static IHost BuildEngineHost(string[] args)
{
    var engineBuilder = new HostBuilder()
        .ConfigureAppConfiguration((hostContext, config) =>
        {
            config.SetBasePath(Directory.GetCurrentDirectory());
            config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
            config.AddEnvironmentVariables();
            if(hostContext.HostingEnvironment.IsDevelopment())
                config.AddUserSecrets<EngineOptions>();
        })
        .ConfigureServices((hostContext, services) =>
        {
            services.Configure<EngineOptions>(hostContext.Configuration.GetSection("EngineOptions"));
            services.AddHostedService<EtlEngineService>();
        })
        .ConfigureLogging((hostContext, logging) =>
        {
            logging.AddConfiguration(hostContext.Configuration.GetSection("Logging"));
            logging.AddConsole();
        });
    return engineBuilder.Build();
}

更新:在配置应用程序之前需要配置主机

.ConfigureHostConfiguration(config =>
{
    config.AddCommandLine(args);
    config.AddEnvironmentVariables();
})

这在 .ConfigureAppConfiguration() 之前调用并从任何名为 "Environment" 的变量加载,这意味着我不必使用 ASPNET_ENVIRONMENT.

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-2.2

What is the proper way to have this set when building my own host so that I can conditionally add user secrets to my configuration when building the host?

正确的方法是不要在 BuildEngineHost 方法中包含您当前拥有的所有代码行。如果您使用的是 ASP.Net Core 2.2,那么您编写的那些设置已经为您设置好了。在您的 Program.cs 文件中,您应该只包含:

public class Program
{
    public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build().Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>();
}

当您查看 GitHub 上的 CreateDefaultBuilder 方法实现时,您会发现默认情况下您尝试执行的操作已经完成。这是 CreateDefaultBuilder 的实现:

public static IWebHostBuilder CreateDefaultBuilder(string[] args)
{
    var builder = new WebHostBuilder();

    if (string.IsNullOrEmpty(builder.GetSetting(WebHostDefaults.ContentRootKey)))
    {
        builder.UseContentRoot(Directory.GetCurrentDirectory());
    }
    if (args != null)
    {
        builder.UseConfiguration(new ConfigurationBuilder().AddCommandLine(args).Build());
    }

    builder.ConfigureAppConfiguration((hostingContext, config) =>
    {
        var env = hostingContext.HostingEnvironment;

        config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
              .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);

        if (env.IsDevelopment())
        {
            var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));
            if (appAssembly != null)
            {
                config.AddUserSecrets(appAssembly, optional: true);
            }
        }

        config.AddEnvironmentVariables();

        if (args != null)
        {
            config.AddCommandLine(args);
        }
    })
    .ConfigureLogging((hostingContext, logging) =>
    {
        logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
        logging.AddConsole();
        logging.AddDebug();
        logging.AddEventSourceLogger();
    }).
    UseDefaultServiceProvider((context, options) =>
    {
        options.ValidateScopes = context.HostingEnvironment.IsDevelopment();
    });

    ConfigureWebDefaults(builder);

    return builder;
}

无论如何,如果您不想使用此实现,那么要回答您的第二个问题,您需要使用添加此行:

config.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);

就在这一行之后:

config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);

env 变量是一种 IHostingEnvironment 类型,需要在您的 BuildEngineHost 方法中注入。

我能够通过在 AppConfiguration 之前调用 ConfigureHostConfiguration() 来使用正确的值初始化托管环境,这在主机中正确设置了我在 Microsoft 的以下文档中遇到的环境值。

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-2.2

private static IHost BuildEngineHost(string[] args)
{
    var engineBuilder = new HostBuilder()
        .ConfigureHostConfiguration(config =>
        {
            config.AddEnvironmentVariables();
            config.AddCommandLine(args);
        })
        .ConfigureAppConfiguration((hostContext, config) =>
        {
            config.SetBasePath(Directory.GetCurrentDirectory());
            config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
            config.AddEnvironmentVariables();
            if(hostContext.HostingEnvironment.IsDevelopment())
                config.AddUserSecrets<EngineOptions>();
        })
        .ConfigureServices((hostContext, services) =>
        {
            services.Configure<EngineOptions>(hostContext.Configuration.GetSection("EngineOptions"));
            services.AddHostedService<EtlEngineService>();
        })
        .ConfigureLogging((hostContext, logging) =>
        {
            logging.AddConfiguration(hostContext.Configuration.GetSection("Logging"));
            logging.AddConsole();
        });
    return engineBuilder.Build();
}