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

Gwi*_*inn 3 c# asp.net-core asp.net-core-3.0

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

在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();

    //...
}

Run Code Online (Sandbox Code Playgroud)

在ASP中,WebHost 不建议使用 .NET Core 3.x ,而应使用.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();

    //...
}
Run Code Online (Sandbox Code Playgroud)

但这仅适用于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;
}
Run Code Online (Sandbox Code Playgroud)

本质上,我已经编写了一个设置a ConfigurationBuilder并将其返回的方法,以便可以重复使用相同的配置。这在实践中可行,但是我两次构建相同的配置。

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

Rhu*_*orl 7

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

为此,您可以利用以下事实:具体配置是在构建其他服务(例如 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();
}
Run Code Online (Sandbox Code Playgroud)

如果您正在配置其他可能影响配置读取位置的服务,那么您可能会发现需要存储对 的引用IWebHostBuilderConfigureAppConfiguration调用IHostBuilder。确保您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();
}
Run Code Online (Sandbox Code Playgroud)

请注意,这有点黑客行为,因此可能不适用于所有情况。


Unc*_*ave 5

您可以清除添加的默认源,CreateDefaultBuilder然后添加IConfiguration使用AddConfiguration extension方法预构建的源。

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();

    //...
}
Run Code Online (Sandbox Code Playgroud)

  • 您的 Startup 类可以通过 DI 在构造函数中接收 IConfiguration (3认同)
  • 最佳答案虽然我有一个附加问题,因为我还在ConfigureAppConfiguration中使用了hostContext,这在上面的示例中不可用。我使用 hostContext 来获取 HostingEnvironment。 (2认同)
  • 这似乎是正确的,但它导致忽略ConfigureWebHostDefaults部分中的一些设置。例如,这种方法完全忽略了 webBuilder.UseUrls() 。有谁知道为什么? (2认同)