如何在 ASP .NET Core 中初始化主机之前读取配置设置?

How to read configuration settings before initializing a Host in ASP .NET Core?

在初始化应用程序主机之前,我需要从应用程序的配置中读取一些设置以设置其他一些东西。

在 ASP .NET Core 2.x 中,在初始化应用程序主机之前读取设置我曾经执行以下操作:

public static void Main(string[] args)
{
    //...

    var configuration = new ConfigurationBuilder()
        .AddEnvironmentVariables()
        .AddCommandLine(args)
        .AddJsonFile("appsettings.json")
        .Build();

    //Do something useful with the configuration...

    var host = WebHost.CreateDefaultBuilder()
        .UseStartup<Startup>()
        .UseConfiguration(configuration)
        .Build();

    //...
}

在 ASP .NET Core 3.x WebHost has been deprecated in favor of .NET Generic Host.
.NET 通用主机只有 .ConfigureHostConfiguration().ConfigureAppConfiguration() 不将构建的配置作为参数,而是只接受用于设置配置的委托。

对于 HTTP 工作负载,您仍然可以使用 .UseConfiguration() 方法,它已由 IWebHostBuilder 公开,并且与以前基本相同:

public static void Main(string[] args)
{
    //...

    var configuration = new ConfigurationBuilder()
        .AddEnvironmentVariables()
        .AddCommandLine(args)
        .AddJsonFile("appsettings.json")
        .Build();

    //Do something useful with the configuration...

    var host = Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>()
                .UseConfiguration(configuration);
        })
        .Build();

    //...
}

但这仅适用于 HTTP 工作负载,不适用于 Worker Services.

为了在设置主机之前获取配置,我想出了以下方法:

public static void Main(string[] args)
{
    //...

    var configuration = ConfigureConfigurationBuilder(args)
        .Build();

    //Do something useful with the configuration...

    var host = Host.CreateDefaultBuilder(args)
        .ConfigureAppConfiguration(builder => ConfigureConfigurationBuilder(args, builder))
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        })
        .Build();

    //...
}

public static IConfigurationBuilder ConfigureConfigurationBuilder(string[] args, IConfigurationBuilder configurationBuilder = null)
{
    configurationBuilder ??= new ConfigurationBuilder();

    configurationBuilder
        .AddEnvironmentVariables()
        .AddCommandLine(args)
        .AddJsonFile("appsettings.json");

    return configurationBuilder;
}

基本上我写了一个设置 ConfigurationBuilder 和 returns 的方法,这样我就可以重复使用相同的配置。这在实践中有效,但我构建了两次相同的配置。

是否有 simpler/more 正确的方法 (适用于 HTTP 工作负载和非 HTTP 工作负载) 在设置主机之前构建和重用配置?

正确的问题是,你的配置真的需要配置吗?可以用别的文件,直接绑定entity

configuration.GetSection("entity").Bind(entity);

如果我不明白你的意思,我所知道的是你需要它来进行依赖注入的设置,或者你不能使用它,所以你可以使用扩展来代替你的服务集合以根据您的配置执行您想要的操作,并在您的容器中进行设置。

您可以清除 CreateDefaultBuilder 添加的默认源,然后使用 AddConfiguration extension method.

添加预构建的 IConfiguration
public static void Main(string[] args)
{
    //...

    var configuration = new ConfigurationBuilder()
        .AddEnvironmentVariables()
        .AddCommandLine(args)
        .AddJsonFile("appsettings.json")
        .Build();

    //Do something useful with the configuration...

    var host = Host.CreateDefaultBuilder(args)
        .ConfigureAppConfiguration(builder =>
        {
            builder.Sources.Clear();
            builder.AddConfiguration(configuration);
        })
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        })
        .Build();

    //...
}

默认情况下 ConfigureAppConfiguration() 将根据文档 Default builder settings 加载 appsettings.json

或者,如果您无法访问您的配置或出现 System.NullReferenceException: 'Object reference not set to an instance ofan object.' 错误,这意味着 IHostBuilder 在其基本路径中看不到 json 文件。

检查或更改 appsettings.json 文件属性,如下图所示:

  1. 将“生成操作”设置为“内容”
  2. 将“复制到输出目录”设置为“如果更新则复制”

UncleDave 的回答当然是最好和最正确的方法,但是如果你想使用默认配置而不自己重新创建逻辑,那么访问 IConfiguration 并不容易和 IWebHostBuilder 在同一个地方。

为此,您可以利用在构建 Web 主机等其他服务之前先构建具体配置这一事实。您可以使用 ConfigureAppConfiguration() 访问配置,然后使用它继续构建 IWebHostBuilder.

例如:

public static async Task Main(string[] args)
{
    var hostBuilder = Host.CreateDefaultBuilder(args);
    var builder = hostBuilder
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();

            // make sure to put this at the end of this method
            webBuilder.ConfigureAppConfiguration(configBuilder =>
            {
                // compile a temporary configuration instance
                var configuration = configBuilder.Build();

                // Check config values as you would normally
                var myConfig = new MyConfig();
                configuration.Bind("MyConfigSection", myConfig);
                if (myConfig.UseSentryLogging)
                {
                    // configure the web host based on config
                    webBuilder.UseSentry();
                }
            });
        });

    var host = builder.Build();
    await host.RunWithTasksAsync();
}

如果您配置的其他服务可能会影响配置的读取位置,那么您可能会发现需要存储对 IWebHostBuilder 的引用并在 [=18= 上调用 ConfigureAppConfiguration ] 反而。确保最后调用 ConfigureAppConfiguration,以便可以先进行其他配置设置并正确访问它:

public static async Task Main(string[] args)
{
    // we store the reference to the webHostBuilder so we can access it outside of ConfigureWebHost
    IWebHostBuilder _webBuilder = null;

    var hostBuilder = Host.CreateDefaultBuilder(args);
    var builder = hostBuilder
        .ConfigureWebHostDefaults(webBuilder =>
        {
            // store the builder for later
            _webBuilder = webBuilder;
            webBuilder.UseStartup<Startup>();
        })
        .ReadConfigFromSomewhereElse()
        .ConfigureAppConfiguration(configBuilder =>
        {
            // compile a temporary configuration instance
            var configuration = configBuilder.Build();

            // Check config values as you would normally
            var myConfig = new MyConfig();
            configuration.Bind("MyConfigSection", myConfig);
            if (myConfig.UseSentryLogging)
            {
                // configure the web host based on config
                _webBuilder.UseSentry();
            }
        });

    var host = builder.Build();
    await host.RunWithTasksAsync();
}

请注意,这有点乱七八糟,因此可能并非在所有情况下都有效。