From 88b3e887fcc249625c769ae036e0164ab7cff346 Mon Sep 17 00:00:00 2001 From: Stephen Halter Date: Wed, 14 Jul 2021 13:11:45 -0700 Subject: [PATCH] Replace Configuration with ConfigurationManager --- .../src/BootstrapHostBuilder.cs | 6 +- src/DefaultBuilder/src/Configuration.cs | 220 ------------------ .../src/ConfigureHostBuilder.cs | 4 +- .../src/ConfigureWebHostBuilder.cs | 4 +- .../src/PublicAPI.Unshipped.txt | 8 +- .../src/WebApplicationBuilder.cs | 5 +- src/DefaultBuilder/src/WebHostEnvironment.cs | 21 +- .../ConfigurationTests.cs | 142 ----------- 8 files changed, 9 insertions(+), 401 deletions(-) delete mode 100644 src/DefaultBuilder/src/Configuration.cs delete mode 100644 src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/ConfigurationTests.cs diff --git a/src/DefaultBuilder/src/BootstrapHostBuilder.cs b/src/DefaultBuilder/src/BootstrapHostBuilder.cs index 8fdd740a83f2..54f79059e228 100644 --- a/src/DefaultBuilder/src/BootstrapHostBuilder.cs +++ b/src/DefaultBuilder/src/BootstrapHostBuilder.cs @@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Hosting // This exists solely to bootstrap the configuration internal class BootstrapHostBuilder : IHostBuilder { - private readonly Configuration _configuration; + private readonly ConfigurationManager _configuration; private readonly WebHostEnvironment _environment; private readonly HostBuilderContext _hostContext; @@ -21,7 +21,7 @@ internal class BootstrapHostBuilder : IHostBuilder private readonly List> _configureHostActions = new(); private readonly List> _configureAppActions = new(); - public BootstrapHostBuilder(Configuration configuration, WebHostEnvironment webHostEnvironment) + public BootstrapHostBuilder(ConfigurationManager configuration, WebHostEnvironment webHostEnvironment) { _configuration = configuration; _environment = webHostEnvironment; @@ -95,7 +95,6 @@ internal void RunConfigurationCallbacks() // Configuration doesn't auto-update during the bootstrap phase to reduce I/O, // but we do need to update between host and app configuration so the right environment is used. - _configuration.Update(); _environment.ApplyConfigurationSettings(_configuration); foreach (var configureAppAction in _configureAppActions) @@ -103,7 +102,6 @@ internal void RunConfigurationCallbacks() configureAppAction(_hostContext, _configuration); } - _configuration.Update(); _environment.ApplyConfigurationSettings(_configuration); } } diff --git a/src/DefaultBuilder/src/Configuration.cs b/src/DefaultBuilder/src/Configuration.cs deleted file mode 100644 index 0ac709f97b63..000000000000 --- a/src/DefaultBuilder/src/Configuration.cs +++ /dev/null @@ -1,220 +0,0 @@ -// 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; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Threading; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Primitives; - -namespace Microsoft.AspNetCore.Builder -{ - /// - /// Configuration is mutable configuration object. It is both an and an . - /// As sources are added, it updates its current view of configuration. Once Build is called, configuration is frozen. - /// - public sealed class Configuration : IConfigurationRoot, IConfigurationBuilder, IDisposable - { - private readonly ConfigurationSources _sources; - private ConfigurationRoot _configurationRoot; - - private ConfigurationReloadToken _changeToken = new(); - private IDisposable? _changeTokenRegistration; - - /// - /// Creates an empty mutable configuration object that is both an and an . - /// - public Configuration() - { - _sources = new ConfigurationSources(this); - - // Make sure there's some default storage since there are no default providers. - this.AddInMemoryCollection(); - - Update(); - } - - /// - /// Automatically update the on changes. - /// If , will manually update the . - /// - internal bool AutoUpdate { get; set; } = true; - - /// - public string this[string key] { get => _configurationRoot[key]; set => _configurationRoot[key] = value; } - - /// - public IConfigurationSection GetSection(string key) => new ConfigurationSection(this, key); - - /// - public IEnumerable GetChildren() => GetChildrenImplementation(null); - - IDictionary IConfigurationBuilder.Properties { get; } = new Dictionary(); - - IList IConfigurationBuilder.Sources => _sources; - - IEnumerable IConfigurationRoot.Providers => _configurationRoot.Providers; - - /// - /// Manually update the to reflect changes. - /// It is not necessary to call this if is . - /// - [MemberNotNull(nameof(_configurationRoot))] - internal void Update() - { - var newConfiguration = BuildConfigurationRoot(); - var prevConfiguration = _configurationRoot; - - _configurationRoot = newConfiguration; - - _changeTokenRegistration?.Dispose(); - (prevConfiguration as IDisposable)?.Dispose(); - - _changeTokenRegistration = ChangeToken.OnChange(() => newConfiguration.GetReloadToken(), RaiseChanged); - RaiseChanged(); - } - - /// - void IDisposable.Dispose() - { - _changeTokenRegistration?.Dispose(); - _configurationRoot?.Dispose(); - } - - IConfigurationBuilder IConfigurationBuilder.Add(IConfigurationSource source) - { - _sources.Add(source ?? throw new ArgumentNullException(nameof(source))); - return this; - } - - IConfigurationRoot IConfigurationBuilder.Build() => BuildConfigurationRoot(); - - IChangeToken IConfiguration.GetReloadToken() => _changeToken; - - void IConfigurationRoot.Reload() => _configurationRoot.Reload(); - - private void NotifySourcesChanged() - { - if (AutoUpdate) - { - Update(); - } - } - - private ConfigurationRoot BuildConfigurationRoot() - { - var providers = new List(); - foreach (var source in _sources) - { - var provider = source.Build(this); - providers.Add(provider); - } - return new ConfigurationRoot(providers); - } - - private void RaiseChanged() - { - var previousToken = Interlocked.Exchange(ref _changeToken, new ConfigurationReloadToken()); - previousToken.OnReload(); - } - - /// - /// Gets the immediate children sub-sections of configuration root based on key. - /// - /// Key of a section of which children to retrieve. - /// Immediate children sub-sections of section specified by key. - private IEnumerable GetChildrenImplementation(string? path) - { - // From https://github.com/dotnet/runtime/blob/01b7e73cd378145264a7cb7a09365b41ed42b240/src/libraries/Microsoft.Extensions.Configuration/src/InternalConfigurationRootExtensions.cs - return _configurationRoot.Providers - .Aggregate(Enumerable.Empty(), - (seed, source) => source.GetChildKeys(seed, path)) - .Distinct(StringComparer.OrdinalIgnoreCase) - .Select(key => _configurationRoot.GetSection(path == null ? key : ConfigurationPath.Combine(path, key))); - } - - private class ConfigurationSources : IList - { - private readonly List _sources = new(); - private readonly Configuration _config; - - public ConfigurationSources(Configuration config) - { - _config = config; - } - - public IConfigurationSource this[int index] - { - get => _sources[index]; - set - { - _sources[index] = value; - _config.NotifySourcesChanged(); - } - } - - public int Count => _sources.Count; - - public bool IsReadOnly => false; - - public void Add(IConfigurationSource item) - { - _sources.Add(item); - _config.NotifySourcesChanged(); - } - - public void Clear() - { - _sources.Clear(); - _config.NotifySourcesChanged(); - } - - public bool Contains(IConfigurationSource item) - { - return _sources.Contains(item); - } - - public void CopyTo(IConfigurationSource[] array, int arrayIndex) - { - _sources.CopyTo(array, arrayIndex); - } - - public IEnumerator GetEnumerator() - { - return _sources.GetEnumerator(); - } - - public int IndexOf(IConfigurationSource item) - { - return _sources.IndexOf(item); - } - - public void Insert(int index, IConfigurationSource item) - { - _sources.Insert(index, item); - _config.NotifySourcesChanged(); - } - - public bool Remove(IConfigurationSource item) - { - var removed = _sources.Remove(item); - _config.NotifySourcesChanged(); - return removed; - } - - public void RemoveAt(int index) - { - _sources.RemoveAt(index); - _config.NotifySourcesChanged(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - } - } -} diff --git a/src/DefaultBuilder/src/ConfigureHostBuilder.cs b/src/DefaultBuilder/src/ConfigureHostBuilder.cs index 4e36de917b47..a79242d4ddc3 100644 --- a/src/DefaultBuilder/src/ConfigureHostBuilder.cs +++ b/src/DefaultBuilder/src/ConfigureHostBuilder.cs @@ -21,12 +21,12 @@ public sealed class ConfigureHostBuilder : IHostBuilder public IDictionary Properties { get; } = new Dictionary(); private readonly WebHostEnvironment _environment; - private readonly Configuration _configuration; + private readonly ConfigurationManager _configuration; private readonly IServiceCollection _services; private readonly HostBuilderContext _context; - internal ConfigureHostBuilder(Configuration configuration, WebHostEnvironment environment, IServiceCollection services) + internal ConfigureHostBuilder(ConfigurationManager configuration, WebHostEnvironment environment, IServiceCollection services) { _configuration = configuration; _environment = environment; diff --git a/src/DefaultBuilder/src/ConfigureWebHostBuilder.cs b/src/DefaultBuilder/src/ConfigureWebHostBuilder.cs index e905440709be..0ac2ec7045d7 100644 --- a/src/DefaultBuilder/src/ConfigureWebHostBuilder.cs +++ b/src/DefaultBuilder/src/ConfigureWebHostBuilder.cs @@ -16,13 +16,13 @@ namespace Microsoft.AspNetCore.Builder public sealed class ConfigureWebHostBuilder : IWebHostBuilder { private readonly WebHostEnvironment _environment; - private readonly Configuration _configuration; + private readonly ConfigurationManager _configuration; private readonly Dictionary _settings = new(StringComparer.OrdinalIgnoreCase); private readonly IServiceCollection _services; private readonly WebHostBuilderContext _context; - internal ConfigureWebHostBuilder(Configuration configuration, WebHostEnvironment environment, IServiceCollection services) + internal ConfigureWebHostBuilder(ConfigurationManager configuration, WebHostEnvironment environment, IServiceCollection services) { _configuration = configuration; _environment = environment; diff --git a/src/DefaultBuilder/src/PublicAPI.Unshipped.txt b/src/DefaultBuilder/src/PublicAPI.Unshipped.txt index 3c537d7e886b..2b9fc569dbfa 100644 --- a/src/DefaultBuilder/src/PublicAPI.Unshipped.txt +++ b/src/DefaultBuilder/src/PublicAPI.Unshipped.txt @@ -1,10 +1,4 @@ #nullable enable -Microsoft.AspNetCore.Builder.Configuration -Microsoft.AspNetCore.Builder.Configuration.Configuration() -> void -Microsoft.AspNetCore.Builder.Configuration.GetChildren() -> System.Collections.Generic.IEnumerable! -Microsoft.AspNetCore.Builder.Configuration.GetSection(string! key) -> Microsoft.Extensions.Configuration.IConfigurationSection! -Microsoft.AspNetCore.Builder.Configuration.this[string! key].get -> string! -Microsoft.AspNetCore.Builder.Configuration.this[string! key].set -> void Microsoft.AspNetCore.Builder.ConfigureHostBuilder Microsoft.AspNetCore.Builder.ConfigureHostBuilder.ConfigureAppConfiguration(System.Action! configureDelegate) -> Microsoft.Extensions.Hosting.IHostBuilder! Microsoft.AspNetCore.Builder.ConfigureHostBuilder.ConfigureContainer(System.Action! configureDelegate) -> Microsoft.Extensions.Hosting.IHostBuilder! @@ -33,7 +27,7 @@ Microsoft.AspNetCore.Builder.WebApplication.StopAsync(System.Threading.Cancellat Microsoft.AspNetCore.Builder.WebApplication.Urls.get -> System.Collections.Generic.ICollection! Microsoft.AspNetCore.Builder.WebApplicationBuilder Microsoft.AspNetCore.Builder.WebApplicationBuilder.Build() -> Microsoft.AspNetCore.Builder.WebApplication! -Microsoft.AspNetCore.Builder.WebApplicationBuilder.Configuration.get -> Microsoft.AspNetCore.Builder.Configuration! +Microsoft.AspNetCore.Builder.WebApplicationBuilder.Configuration.get -> Microsoft.Extensions.Configuration.ConfigurationManager! Microsoft.AspNetCore.Builder.WebApplicationBuilder.Environment.get -> Microsoft.AspNetCore.Hosting.IWebHostEnvironment! Microsoft.AspNetCore.Builder.WebApplicationBuilder.Host.get -> Microsoft.AspNetCore.Builder.ConfigureHostBuilder! Microsoft.AspNetCore.Builder.WebApplicationBuilder.Logging.get -> Microsoft.Extensions.Logging.ILoggingBuilder! diff --git a/src/DefaultBuilder/src/WebApplicationBuilder.cs b/src/DefaultBuilder/src/WebApplicationBuilder.cs index 2b02fe15412d..349f75ded5a8 100644 --- a/src/DefaultBuilder/src/WebApplicationBuilder.cs +++ b/src/DefaultBuilder/src/WebApplicationBuilder.cs @@ -62,9 +62,6 @@ internal WebApplicationBuilder(Assembly? callingAssembly, string[]? args = null) // Configuration changes made by ConfigureDefaults(args) were already picked up by the BootstrapHostBuilder, // so we ignore changes to config until ConfigureDefaults completes. _deferredHostBuilder.ConfigurationEnabled = true; - // Now that consuming code can start modifying Configuration, we need to automatically rebuild on modification. - // To this point, we've been manually calling Configuration.UpdateConfiguration() only when needed to reduce I/O. - Configuration.AutoUpdate = true; } /// @@ -80,7 +77,7 @@ internal WebApplicationBuilder(Assembly? callingAssembly, string[]? args = null) /// /// A collection of configuration providers for the application to compose. This is useful for adding new configuration sources and providers. /// - public Configuration Configuration { get; } = new() { AutoUpdate = false }; + public ConfigurationManager Configuration { get; } = new(); /// /// A collection of logging providers for the application to compose. This is useful for adding new logging providers. diff --git a/src/DefaultBuilder/src/WebHostEnvironment.cs b/src/DefaultBuilder/src/WebHostEnvironment.cs index 757577c3bf68..323079642cf0 100644 --- a/src/DefaultBuilder/src/WebHostEnvironment.cs +++ b/src/DefaultBuilder/src/WebHostEnvironment.cs @@ -36,16 +36,12 @@ public WebHostEnvironment(Assembly? callingAssembly = null) { WebRootPath = wwwroot; } - - if (this.IsDevelopment()) - { - StaticWebAssetsLoader.UseStaticWebAssets(this, new Configuration()); - } } public void ApplyConfigurationSettings(IConfiguration configuration) { ReadConfigurationSettings(configuration); + if (this.IsDevelopment()) { StaticWebAssetsLoader.UseStaticWebAssets(this, configuration); @@ -81,20 +77,6 @@ internal void CopyPropertiesTo(IWebHostEnvironment destination) destination.WebRootPath = WebRootPath; } - public void ResolveFileProviders(IConfiguration configuration) - { - if (Directory.Exists(ContentRootPath)) - { - ContentRootFileProvider = new PhysicalFileProvider(ContentRootPath); - } - - if (Directory.Exists(WebRootPath)) - { - WebRootFileProvider = new PhysicalFileProvider(WebRootPath); - } - - } - public string ApplicationName { get; set; } public string EnvironmentName { get; set; } @@ -110,7 +92,6 @@ public IFileProvider WebRootFileProvider set => _webRootFileProvider = value; } - public string ContentRootPath { get => _contentRootPath; diff --git a/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/ConfigurationTests.cs b/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/ConfigurationTests.cs deleted file mode 100644 index 75668b4c14bb..000000000000 --- a/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/ConfigurationTests.cs +++ /dev/null @@ -1,142 +0,0 @@ -// 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.AspNetCore.Builder; -using Microsoft.Extensions.Configuration; -using Xunit; - -namespace Microsoft.AspNetCore.Tests -{ - public class ConfigurationTests - { - [Fact] - public void AutoUpdatesByDefault() - { - var config = new Configuration(); - - Assert.True(config.AutoUpdate); - - config.AddInMemoryCollection(new Dictionary - { - { "TestKey", "TestValue" }, - }); - - Assert.Equal("TestValue", config["TestKey"]); - } - - [Fact] - public void AutoUpdateTriggersReloadTokenOnSourceModification() - { - var config = new Configuration(); - - var reloadToken = ((IConfiguration)config).GetReloadToken(); - - Assert.False(reloadToken.HasChanged); - - config.AddInMemoryCollection(new Dictionary - { - { "TestKey", "TestValue" }, - }); - - Assert.True(reloadToken.HasChanged); - } - - [Fact] - public void DoesNotAutoUpdateWhenAutoUpdateDisabled() - { - var config = new Configuration - { - AutoUpdate = false, - }; - - config.AddInMemoryCollection(new Dictionary - { - { "TestKey", "TestValue" }, - }); - - Assert.Null(config["TestKey"]); - - config.Update(); - - Assert.Equal("TestValue", config["TestKey"]); - } - - [Theory] - [InlineData(true)] - [InlineData(false)] - public void ManualUpdateTriggersReloadTokenWithOrWithoutAutoUpdate(bool autoUpdate) - { - var config = new Configuration - { - AutoUpdate = autoUpdate, - }; - - var manualReloadToken = ((IConfiguration)config).GetReloadToken(); - - Assert.False(manualReloadToken.HasChanged); - - config.Update(); - - Assert.True(manualReloadToken.HasChanged); - } - - [Theory] - [InlineData(true)] - [InlineData(false)] - public void SettingValuesWorksWithOrWithoutAutoUpdate(bool autoUpdate) - { - var config = new Configuration - { - AutoUpdate = autoUpdate, - ["TestKey"] = "TestValue", - }; - - Assert.Equal("TestValue", config["TestKey"]); - } - - [Theory] - [InlineData(true)] - [InlineData(false)] - public void SettingValuesDoesNotTriggerReloadTokenWithOrWithoutAutoUpdate(bool autoUpdate) - { - var config = new Configuration - { - AutoUpdate = autoUpdate, - }; - - var reloadToken = ((IConfiguration)config).GetReloadToken(); - - config["TestKey"] = "TestValue"; - - Assert.Equal("TestValue", config["TestKey"]); - - // ConfigurationRoot doesn't fire the token today when the setter is called. Maybe we should change that. - // At least you can manually call Configuration.Update() to fire a reload though this reloads all sources unnecessarily. - Assert.False(reloadToken.HasChanged); - } - - [Theory] - [InlineData(true)] - [InlineData(false)] - public void SettingIConfigurationBuilderPropertiesWorksWithoutAutoUpdate(bool autoUpdate) - { - var config = new Configuration - { - AutoUpdate = autoUpdate, - }; - - var configBuilder = (IConfigurationBuilder)config; - - var reloadToken = ((IConfiguration)config).GetReloadToken(); - - configBuilder.Properties["TestKey"] = "TestValue"; - - Assert.Equal("TestValue", configBuilder.Properties["TestKey"]); - - // Changing properties should not change config keys or fire reload token. - Assert.Null(config["TestKey"]); - Assert.False(reloadToken.HasChanged); - } - } -}