Ordering sensitive configuration #582
This commit is contained in:
parent
3ea44c6f75
commit
ae47bb21a6
|
|
@ -2,10 +2,8 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting.Server;
|
using Microsoft.AspNetCore.Hosting.Server;
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Hosting
|
namespace Microsoft.AspNetCore.Hosting
|
||||||
|
|
@ -20,20 +18,6 @@ namespace Microsoft.AspNetCore.Hosting
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IWebHost Build();
|
IWebHost Build();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the raw settings to be used by the web host. Values specified here will override
|
|
||||||
/// the configuration set by <see cref="UseConfiguration(IConfiguration)"/>.
|
|
||||||
/// </summary>
|
|
||||||
IDictionary<string, string> Settings { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Specify the <see cref="IConfiguration"/> to be used by the web host. If no configuration is
|
|
||||||
/// provided to the builder, the default configuration will be used.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="configuration">The <see cref="IConfiguration"/> to be used.</param>
|
|
||||||
/// <returns>The <see cref="IWebHostBuilder"/>.</returns>
|
|
||||||
IWebHostBuilder UseConfiguration(IConfiguration configuration);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Specify the <see cref="IServerFactory"/> to be used by the web host.
|
/// Specify the <see cref="IServerFactory"/> to be used by the web host.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -63,11 +47,18 @@ namespace Microsoft.AspNetCore.Hosting
|
||||||
IWebHostBuilder Configure(Action<IApplicationBuilder> configureApplication);
|
IWebHostBuilder Configure(Action<IApplicationBuilder> configureApplication);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Add or replace a setting in <see cref="Settings"/>.
|
/// Add or replace a setting in the configuration.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="key">The key of the setting to add or replace.</param>
|
/// <param name="key">The key of the setting to add or replace.</param>
|
||||||
/// <param name="value">The value of the setting to add or replace.</param>
|
/// <param name="value">The value of the setting to add or replace.</param>
|
||||||
/// <returns>The <see cref="IWebHostBuilder"/>.</returns>
|
/// <returns>The <see cref="IWebHostBuilder"/>.</returns>
|
||||||
IWebHostBuilder UseSetting(string key, string value);
|
IWebHostBuilder UseSetting(string key, string value);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the setting value from the configuration.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">The key of the setting to look up.</param>
|
||||||
|
/// <returns>The value the setting currently contains.</returns>
|
||||||
|
string GetSetting(string key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Hosting.Internal
|
||||||
|
{
|
||||||
|
public static class IConfigurationExtensions
|
||||||
|
{
|
||||||
|
// Temporary until Configuration/issues/370 is implemented.
|
||||||
|
public static IEnumerable<KeyValuePair<string, string>> GetFlattenedSettings(this IConfiguration configuration)
|
||||||
|
{
|
||||||
|
var stack = new Stack<IConfiguration>();
|
||||||
|
stack.Push(configuration);
|
||||||
|
|
||||||
|
while (stack.Count > 0)
|
||||||
|
{
|
||||||
|
var config = stack.Pop();
|
||||||
|
var section = config as IConfigurationSection;
|
||||||
|
|
||||||
|
if (section != null)
|
||||||
|
{
|
||||||
|
yield return new KeyValuePair<string, string>(section.Path, section.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var child in config.GetChildren())
|
||||||
|
{
|
||||||
|
stack.Push(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Hosting
|
namespace Microsoft.AspNetCore.Hosting.Internal
|
||||||
{
|
{
|
||||||
public class WebHostConfiguration
|
public class WebHostConfiguration
|
||||||
{
|
{
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.Versioning;
|
using System.Runtime.Versioning;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
|
@ -28,7 +27,7 @@ namespace Microsoft.AspNetCore.Hosting
|
||||||
private readonly IHostingEnvironment _hostingEnvironment;
|
private readonly IHostingEnvironment _hostingEnvironment;
|
||||||
private readonly ILoggerFactory _loggerFactory;
|
private readonly ILoggerFactory _loggerFactory;
|
||||||
|
|
||||||
private IConfiguration _config;
|
private IConfiguration _config = new ConfigurationBuilder().AddInMemoryCollection().Build();
|
||||||
private WebHostOptions _options;
|
private WebHostOptions _options;
|
||||||
|
|
||||||
private Action<IServiceCollection> _configureServices;
|
private Action<IServiceCollection> _configureServices;
|
||||||
|
|
@ -40,26 +39,12 @@ namespace Microsoft.AspNetCore.Hosting
|
||||||
// Only one of these should be set
|
// Only one of these should be set
|
||||||
private IServerFactory _serverFactory;
|
private IServerFactory _serverFactory;
|
||||||
|
|
||||||
private IDictionary<string, string> _settings = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
|
||||||
|
|
||||||
public WebHostBuilder()
|
public WebHostBuilder()
|
||||||
{
|
{
|
||||||
_hostingEnvironment = new HostingEnvironment();
|
_hostingEnvironment = new HostingEnvironment();
|
||||||
_loggerFactory = new LoggerFactory();
|
_loggerFactory = new LoggerFactory();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the raw settings to be used by the web host. Values specified here will override
|
|
||||||
/// the configuration set by <see cref="UseConfiguration(IConfiguration)"/>.
|
|
||||||
/// </summary>
|
|
||||||
public IDictionary<string, string> Settings
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _settings;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Add or replace a setting in <see cref="Settings"/>.
|
/// Add or replace a setting in <see cref="Settings"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -68,20 +53,18 @@ namespace Microsoft.AspNetCore.Hosting
|
||||||
/// <returns>The <see cref="IWebHostBuilder"/>.</returns>
|
/// <returns>The <see cref="IWebHostBuilder"/>.</returns>
|
||||||
public IWebHostBuilder UseSetting(string key, string value)
|
public IWebHostBuilder UseSetting(string key, string value)
|
||||||
{
|
{
|
||||||
_settings[key] = value;
|
_config[key] = value;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Specify the <see cref="IConfiguration"/> to be used by the web host. If no configuration is
|
/// Get the setting value from the configuration.
|
||||||
/// provided to the builder, the default configuration will be used.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="configuration">The <see cref="IConfiguration"/> to be used.</param>
|
/// <param name="key">The key of the setting to look up.</param>
|
||||||
/// <returns>The <see cref="IWebHostBuilder"/>.</returns>
|
/// <returns>The value the setting currently contains.</returns>
|
||||||
public IWebHostBuilder UseConfiguration(IConfiguration configuration)
|
public string GetSetting(string key)
|
||||||
{
|
{
|
||||||
_config = configuration;
|
return _config[key];
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -187,15 +170,6 @@ namespace Microsoft.AspNetCore.Hosting
|
||||||
|
|
||||||
private IServiceCollection BuildHostingServices()
|
private IServiceCollection BuildHostingServices()
|
||||||
{
|
{
|
||||||
// Apply the configuration settings
|
|
||||||
var configuration = _config ?? WebHostConfiguration.GetDefault();
|
|
||||||
|
|
||||||
var mergedConfiguration = new ConfigurationBuilder()
|
|
||||||
.Add(new IncludedConfigurationProvider(configuration))
|
|
||||||
.AddInMemoryCollection(_settings)
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
_config = mergedConfiguration;
|
|
||||||
_options = new WebHostOptions(_config);
|
_options = new WebHostOptions(_config);
|
||||||
|
|
||||||
var services = new ServiceCollection();
|
var services = new ServiceCollection();
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using Microsoft.AspNetCore.Hosting.Internal;
|
||||||
using Microsoft.AspNetCore.Hosting.Server;
|
using Microsoft.AspNetCore.Hosting.Server;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
|
|
@ -21,6 +22,16 @@ namespace Microsoft.AspNetCore.Hosting
|
||||||
return builder.UseConfiguration(WebHostConfiguration.GetDefault(args));
|
return builder.UseConfiguration(WebHostConfiguration.GetDefault(args));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IWebHostBuilder UseConfiguration(this IWebHostBuilder builder, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
foreach (var setting in configuration.GetFlattenedSettings())
|
||||||
|
{
|
||||||
|
builder.UseSetting(setting.Key, setting.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
public static IWebHostBuilder UseCaptureStartupErrors(this IWebHostBuilder hostBuilder, bool captureStartupError)
|
public static IWebHostBuilder UseCaptureStartupErrors(this IWebHostBuilder hostBuilder, bool captureStartupError)
|
||||||
{
|
{
|
||||||
return hostBuilder.UseSetting(WebHostDefaults.CaptureStartupErrorsKey, captureStartupError ? "true" : "false");
|
return hostBuilder.UseSetting(WebHostDefaults.CaptureStartupErrorsKey, captureStartupError ? "true" : "false");
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.TestHost
|
||||||
|
|
||||||
public TestServer(IWebHostBuilder builder)
|
public TestServer(IWebHostBuilder builder)
|
||||||
{
|
{
|
||||||
if (!builder.Settings.ContainsKey(WebHostDefaults.CaptureStartupErrorsKey))
|
if (string.IsNullOrEmpty(builder.GetSetting(WebHostDefaults.CaptureStartupErrorsKey)))
|
||||||
{
|
{
|
||||||
builder.UseCaptureStartupErrors(false);
|
builder.UseCaptureStartupErrors(false);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -124,9 +124,10 @@ namespace Microsoft.AspNetCore.Hosting
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void CaptureStartupErrorsByDefault()
|
public void DefaultConfigurationCapturesStartupErrors()
|
||||||
{
|
{
|
||||||
var hostBuilder = new WebHostBuilder()
|
var hostBuilder = new WebHostBuilder()
|
||||||
|
.UseDefaultConfiguration()
|
||||||
.UseServer(new TestServer())
|
.UseServer(new TestServer())
|
||||||
.UseStartup<StartupBoom>();
|
.UseStartup<StartupBoom>();
|
||||||
|
|
||||||
|
|
@ -146,6 +147,98 @@ namespace Microsoft.AspNetCore.Hosting
|
||||||
Assert.Equal("A public method named 'ConfigureProduction' or 'Configure' could not be found in the 'Microsoft.AspNetCore.Hosting.Fakes.StartupBoom' type.", exception.Message);
|
Assert.Equal("A public method named 'ConfigureProduction' or 'Configure' could not be found in the 'Microsoft.AspNetCore.Hosting.Fakes.StartupBoom' type.", exception.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CodeBasedSettingsCodeBasedOverride()
|
||||||
|
{
|
||||||
|
var hostBuilder = new WebHostBuilder()
|
||||||
|
.UseSetting(WebHostDefaults.ServerKey, "ServerA")
|
||||||
|
.UseSetting(WebHostDefaults.ServerKey, "ServerB")
|
||||||
|
.UseServer(new TestServer())
|
||||||
|
.UseStartup<StartupNoServices>();
|
||||||
|
|
||||||
|
var host = (WebHost)hostBuilder.Build();
|
||||||
|
|
||||||
|
Assert.Equal("ServerB", host.ServerFactoryLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CodeBasedSettingsConfigBasedOverride()
|
||||||
|
{
|
||||||
|
var settings = new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
{ WebHostDefaults.ServerKey, "ServerB" }
|
||||||
|
};
|
||||||
|
|
||||||
|
var config = new ConfigurationBuilder()
|
||||||
|
.AddInMemoryCollection(settings)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
var hostBuilder = new WebHostBuilder()
|
||||||
|
.UseSetting(WebHostDefaults.ServerKey, "ServerA")
|
||||||
|
.UseConfiguration(config)
|
||||||
|
.UseServer(new TestServer())
|
||||||
|
.UseStartup<StartupNoServices>();
|
||||||
|
|
||||||
|
var host = (WebHost)hostBuilder.Build();
|
||||||
|
|
||||||
|
Assert.Equal("ServerB", host.ServerFactoryLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ConfigBasedSettingsCodeBasedOverride()
|
||||||
|
{
|
||||||
|
var settings = new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
{ WebHostDefaults.ServerKey, "ServerA" }
|
||||||
|
};
|
||||||
|
|
||||||
|
var config = new ConfigurationBuilder()
|
||||||
|
.AddInMemoryCollection(settings)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
var hostBuilder = new WebHostBuilder()
|
||||||
|
.UseConfiguration(config)
|
||||||
|
.UseSetting(WebHostDefaults.ServerKey, "ServerB")
|
||||||
|
.UseServer(new TestServer())
|
||||||
|
.UseStartup<StartupNoServices>();
|
||||||
|
|
||||||
|
var host = (WebHost)hostBuilder.Build();
|
||||||
|
|
||||||
|
Assert.Equal("ServerB", host.ServerFactoryLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ConfigBasedSettingsConfigBasedOverride()
|
||||||
|
{
|
||||||
|
var settings = new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
{ WebHostDefaults.ServerKey, "ServerA" }
|
||||||
|
};
|
||||||
|
|
||||||
|
var config = new ConfigurationBuilder()
|
||||||
|
.AddInMemoryCollection(settings)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
var overrideSettings = new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
{ WebHostDefaults.ServerKey, "ServerB" }
|
||||||
|
};
|
||||||
|
|
||||||
|
var overrideConfig = new ConfigurationBuilder()
|
||||||
|
.AddInMemoryCollection(overrideSettings)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
var hostBuilder = new WebHostBuilder()
|
||||||
|
.UseConfiguration(config)
|
||||||
|
.UseConfiguration(overrideConfig)
|
||||||
|
.UseServer(new TestServer())
|
||||||
|
.UseStartup<StartupNoServices>();
|
||||||
|
|
||||||
|
var host = (WebHost)hostBuilder.Build();
|
||||||
|
|
||||||
|
Assert.Equal("ServerB", host.ServerFactoryLocation);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void UseEnvironmentIsNotOverriden()
|
public void UseEnvironmentIsNotOverriden()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue