Skip to content

Add a type implementing both IConfiguration and IConfigurationBuilder #51770

Closed
@halter73

Description

@halter73

Background and Motivation

When developing a new minimal host for ASP.NET Core (WebApplication, WebApplicationBuilder), we found that it would be useful to be able to read from configuration (e.g. appsettings.json and DOTNET_/ASPNETCORE_ environment variables) while still being able to add new configuration sources. Every time a source is added via the IConfigurationBuilder interface, the IConfiguration updates automatically and immediately.

For this reason, we've temporarily introduced a Configuration type to Microsoft.AspNetCore.Builder that does exactly this. This type belongs in Microsoft.Extensions.Configuration though.

Moving this type will be a breaking change in ASP.NET Core between preview6 and preview7, but we're okay this.

Proposed API

namespace Microsoft.Extensions.Configuration
{
+    public sealed class ConfigurationManager : IConfigurationRoot, IConfigurationBuilder, IDisposable
+    {
+        public ConfigurationManager();
+        public string? this[string key] { get; set; }
+        public IConfigurationSection GetSection(string key);
+        public void Dispose();
+    }

The members that are required to implement IConfigurationBuilder will be implemented explicitly, so members like IList<IConfigurationSource> IConfigurationBuilder.Sources don't pollute intellisense. Extension methods are generally used to add configuration sources.

Usage Examples

WebApplicationBuilder essentially already exposes this type as a public property. The problem it is trying to solve is being able to read config from appsettings.json and DOTNET_/ASPNETCORE_ while configuring the host's IServiceCollection while at the same time being able to add new configuration sources or even change the content root without having to introduce additional build stages.

    using var config = new Config();

    config.AddEnvironmentVariables(prefix: "MyCustomPrefix_");

    if (config["FileConfig"] == "enabled")
    {
        config.AddJsonFile("MyConfig.json", optional: true, reloadOnChange: true);
    } 

    string myValueFromJson = config["JsonConfigValue"];
    // ...

We have docs where we demonstrate manually building an IConfigurationBuilder, reading from the built IConfiguration, and then throwing that away to add a new config source. This is an alternative to that.

Alternative Designs

Update ConfigurationBuilder to implement IConfigurationRoot and basically become this type. It would leave the IConfigurationBuilder methods as normal methods instead of explicit interface implementations like in the proposal.

In the current implementation of Configuration in Microsoft.AspNetCore.Builder, the ChangeBasePath and ChangeFileProvider methods are internal. Consumers of WebApplicationBuilder should generally call builder.WebHost.SetContentRoot() instead. That, in turn, calls these currently-internal methods.

I was thinking an alternative might be an interface or an abstract base class we implement in ASP.NET Core. Perhaps IUpdateConfiguration: IConfigurationRoot, IConfigurationBuilder. I imagine we'd want at least one default implementation in Microsoft.Extensions.Configuration though.

All sources are now reloaded when the IConfigurationBuilder.Properties["FileProvider"] changes.

Risks

It might be confusing to developers if and when this should be used over a plain old ConfigurationBuilder. It also might not be clear if you should call ChangeBasePath or ChangeFileProvider methods instead of the SetBasePath and SetFileProvider methods extension with this new type. The answer is you should.

@maryamariyan @eerhardt @safern @tarekgh @pranavkm @davidfowl @Tratcher

Metadata

Metadata

Assignees

No one assigned

    Labels

    api-approvedAPI was approved in API review, it can be implementedarea-Extensions-ConfigurationblockingMarks issues that we want to fast track in order to unblock other important work

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions