Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/aspnetcore.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Halter <halter73@gmail.com>2021-09-28 04:58:26 +0300
committerStephen Halter <halter73@gmail.com>2021-09-28 05:20:32 +0300
commitfd0f4218b67846c3f85d617dcc1793fafab3b715 (patch)
tree315a0bb682d4853c56f446a84a1fb7c7d3fd4cd1
parent71f98847c214aef18241479d19dc1719b78a6edd (diff)
Preserve IConfigurationProvider typeshalter73/preserve-providers
-rw-r--r--src/DefaultBuilder/src/ConfigurationUnwrapper.cs37
-rw-r--r--src/DefaultBuilder/src/IgnoreFirstLoadConfigurationProvider.cs50
-rw-r--r--src/DefaultBuilder/src/WebApplicationBuilder.cs70
-rw-r--r--src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebApplicationTests.cs12
4 files changed, 126 insertions, 43 deletions
diff --git a/src/DefaultBuilder/src/ConfigurationUnwrapper.cs b/src/DefaultBuilder/src/ConfigurationUnwrapper.cs
new file mode 100644
index 0000000000..54030528d7
--- /dev/null
+++ b/src/DefaultBuilder/src/ConfigurationUnwrapper.cs
@@ -0,0 +1,37 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Linq;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Primitives;
+
+namespace Microsoft.AspNetCore;
+
+internal class ConfigurationUnwrapper : IConfigurationRoot, IDisposable
+{
+ private readonly IConfigurationRoot _configurationRoot;
+
+ public ConfigurationUnwrapper(IConfigurationRoot configurationRoot)
+ {
+ _configurationRoot = configurationRoot;
+ }
+
+ public string this[string key]
+ {
+ get => _configurationRoot[key];
+ set => _configurationRoot[key] = value;
+ }
+
+ public IEnumerable<IConfigurationProvider> Providers =>
+ _configurationRoot.Providers.Select(p => (p as IgnoreFirstLoadConfigurationProvider)?.OriginalConfigurationProvider ?? p);
+
+ public IEnumerable<IConfigurationSection> GetChildren() => _configurationRoot.GetChildren();
+
+ public IChangeToken GetReloadToken() => _configurationRoot.GetReloadToken();
+
+ public IConfigurationSection GetSection(string key) => _configurationRoot.GetSection(key);
+
+ public void Reload() => _configurationRoot.Reload();
+
+ public void Dispose() => (_configurationRoot as IDisposable)?.Dispose();
+}
diff --git a/src/DefaultBuilder/src/IgnoreFirstLoadConfigurationProvider.cs b/src/DefaultBuilder/src/IgnoreFirstLoadConfigurationProvider.cs
new file mode 100644
index 0000000000..b60bd97037
--- /dev/null
+++ b/src/DefaultBuilder/src/IgnoreFirstLoadConfigurationProvider.cs
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Primitives;
+
+namespace Microsoft.AspNetCore;
+
+internal sealed class IgnoreFirstLoadConfigurationProvider : IConfigurationProvider, IDisposable
+{
+ private readonly IConfigurationProvider _configurationProvider;
+
+ private bool _hasIgnoredFirstLoad;
+
+ public IgnoreFirstLoadConfigurationProvider(IConfigurationProvider configurationProvider)
+ {
+ _configurationProvider = configurationProvider;
+ }
+
+ // Give access to the original IConfigurationProvider for unwrapping by ConfigurationUnwarpper.
+ public IConfigurationProvider OriginalConfigurationProvider => _configurationProvider;
+
+ public void Load()
+ {
+ if (!_hasIgnoredFirstLoad)
+ {
+ _hasIgnoredFirstLoad = true;
+ return;
+ }
+
+ _configurationProvider.Load();
+ }
+
+ public IChangeToken GetReloadToken() => _configurationProvider.GetReloadToken();
+
+ public IEnumerable<string> GetChildKeys(IEnumerable<string> earlierKeys, string parentPath) =>
+ _configurationProvider.GetChildKeys(earlierKeys, parentPath);
+
+ public void Set(string key, string value) => _configurationProvider.Set(key, value);
+
+ public bool TryGet(string key, out string value) => _configurationProvider.TryGet(key, out value);
+
+ public override string ToString() => _configurationProvider.ToString()!;
+
+ public override bool Equals(object? obj) => _configurationProvider.Equals(obj);
+
+ public override int GetHashCode() => _configurationProvider.GetHashCode();
+
+ public void Dispose() => (_configurationProvider as IDisposable)?.Dispose();
+}
diff --git a/src/DefaultBuilder/src/WebApplicationBuilder.cs b/src/DefaultBuilder/src/WebApplicationBuilder.cs
index 736e563bbe..35c3f7ee4c 100644
--- a/src/DefaultBuilder/src/WebApplicationBuilder.cs
+++ b/src/DefaultBuilder/src/WebApplicationBuilder.cs
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.Collections;
using System.Diagnostics;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
@@ -16,11 +17,13 @@ namespace Microsoft.AspNetCore.Builder
/// </summary>
public sealed class WebApplicationBuilder
{
+ private const string EndpointRouteBuilderKey = "__EndpointRouteBuilder";
+
private readonly HostBuilder _hostBuilder = new();
private readonly BootstrapHostBuilder _bootstrapHostBuilder;
private readonly WebApplicationServiceCollection _services = new();
private readonly List<KeyValuePair<string, string>> _hostConfigurationValues;
- private const string EndpointRouteBuilderKey = "__EndpointRouteBuilder";
+ private readonly Func<IServiceProvider, IConfiguration> _configurationFactory;
private WebApplication? _builtApplication;
@@ -101,7 +104,8 @@ namespace Microsoft.AspNetCore.Builder
Host = new ConfigureHostBuilder(hostContext, Configuration, Services);
WebHost = new ConfigureWebHostBuilder(webHostContext, Configuration, Services);
- Services.AddSingleton<IConfiguration>(Configuration);
+ _configurationFactory = _ => Configuration;
+ Services.AddSingleton(_configurationFactory);
}
/// <summary>
@@ -168,6 +172,25 @@ namespace Microsoft.AspNetCore.Builder
// Copy the services that were added via WebApplicationBuilder.Services into the final IServiceCollection
_hostBuilder.ConfigureServices((context, services) =>
{
+ // Unwrap the IgnoreFirstLoadConfigurationProviders in IConfigurationRoot.Providers and expose the originals.
+ ServiceDescriptor? configDescriptor = null;
+
+ foreach (var s in services)
+ {
+ if (s.ServiceType == typeof(IConfiguration) && s.ImplementationFactory is not null)
+ {
+ configDescriptor = s;
+ break;
+ }
+ }
+
+ if (configDescriptor is not null)
+ {
+ services.Remove(configDescriptor);
+ services.AddSingleton<IConfiguration>(sp =>
+ new ConfigurationUnwrapper((IConfigurationRoot)configDescriptor.ImplementationFactory!(sp)));
+ }
+
// We've only added services configured by the GenericWebHostBuilder and WebHost.ConfigureWebDefaults
// at this point. HostBuilder news up a new ServiceCollection in HostBuilder.Build() we haven't seen
// until now, so we cannot clear these services even though some are redundant because
@@ -180,7 +203,7 @@ namespace Microsoft.AspNetCore.Builder
// this as well but we still need to remove it from the final configuration
// to avoid cycles in the configuration graph
if (s.ServiceType == typeof(IConfiguration) &&
- s.ImplementationInstance == Configuration)
+ s.ImplementationFactory == _configurationFactory)
{
continue;
}
@@ -310,50 +333,11 @@ namespace Microsoft.AspNetCore.Builder
{
// ConfigurationManager has already loaded its IConfigurationProviders, so we do not need to load it again
// during WebApplicationBuilder.Build(). See https://github.com/dotnet/aspnetcore/issues/37030
+ // ConfigurationUnwrapper will return the original ConfigurationProvider from IConfigurationRoot.Providers.
_configurationProvider = new IgnoreFirstLoadConfigurationProvider(configurationProvider);
}
public IConfigurationProvider Build(IConfigurationBuilder builder) => _configurationProvider;
-
- private sealed class IgnoreFirstLoadConfigurationProvider : IConfigurationProvider, IDisposable
- {
- private readonly IConfigurationProvider _configurationProvider;
-
- private bool _hasIgnoredFirstLoad;
-
- public IgnoreFirstLoadConfigurationProvider(IConfigurationProvider configurationProvider)
- {
- _configurationProvider = configurationProvider;
- }
-
- public void Load()
- {
- if (!_hasIgnoredFirstLoad)
- {
- _hasIgnoredFirstLoad = true;
- return;
- }
-
- _configurationProvider.Load();
- }
-
- public IChangeToken GetReloadToken() => _configurationProvider.GetReloadToken();
-
- public IEnumerable<string> GetChildKeys(IEnumerable<string> earlierKeys, string parentPath) =>
- _configurationProvider.GetChildKeys(earlierKeys, parentPath);
-
- public void Set(string key, string value) => _configurationProvider.Set(key, value);
-
- public bool TryGet(string key, out string value) => _configurationProvider.TryGet(key, out value);
-
- public void Dispose() => (_configurationProvider as IDisposable)?.Dispose();
-
- public override string ToString() => _configurationProvider.ToString()!;
-
- public override bool Equals(object? obj) => _configurationProvider.Equals(obj);
-
- public override int GetHashCode() => _configurationProvider.GetHashCode();
- }
}
}
}
diff --git a/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebApplicationTests.cs b/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebApplicationTests.cs
index 77912f8e03..2580c95013 100644
--- a/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebApplicationTests.cs
+++ b/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebApplicationTests.cs
@@ -1590,6 +1590,18 @@ namespace Microsoft.AspNetCore.Tests
Assert.Equal(1, configSource.ProvidersDisposed);
}
+ [Fact]
+ public void ConfigurationProviderTypesArePreserved()
+ {
+ var builder = WebApplication.CreateBuilder();
+
+ ((IConfigurationBuilder)builder.Configuration).Sources.Add(new RandomConfigurationSource());
+
+ var app = builder.Build();
+
+ Assert.Single(((IConfigurationRoot)app.Configuration).Providers.OfType<RandomConfigurationProvider>());
+ }
+
public class RandomConfigurationSource : IConfigurationSource
{
public int ProvidersBuilt { get; set; }