I've implemented my customs IConfigurationProvider and IConfigurationSource.
public class MyConfigurationSource : IConfigurationSource
{
    public string Foo { get; set; }
    public IConfigurationProvider Build(IConfigurationBuilder builder)
    {
        return new MyConfigurationProvider(this);
    }
}
internal class MyConfigurationProvider : ConfigurationProvider
{
    public MyConfigurationSource Source { get; };
    public MyConfigurationProvider()
    {
        Source = source
    }
    public override void Load()
    {
        // I'd like to assign here my configuration data by using some dependencies
        Data = .... 
    }
}
I do the build of my Configuration in the Startup constructor (I override the configuration created by CreateDefaultBuilder):
var builder = new ConfigurationBuilder()
        .SetBasePath(env.ContentRootPath)
        .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
        .AddEnvironmentVariables()
        .AddMyConfiguration("myfoovalue")
        .Build();
Extension method:
public static IConfigurationBuilder AddMyConfiguration(this IConfigurationBuilder builder, string foo)
{
    return builder.Add(new MyConfigurationSource 
        {
            Foo = url
        });
}
I wish I could somehow inject services to be used in Load method. The problem here is that the configuration build is done in the Startup constructor. I can only inject dependencies that I have available in this constructor: IWebHostEnvironment, IHostEnvironment, IConfiguration and all I added when I built the WebHost. Also these dependencies would have to be passed the moment I call the AddMyConfiguration extension method. How could I use dependencies that don't even exist at that moment?
A bit late answer.
It's obvious there's no way to use the container, that was built using Startup.ConfigureServices, in the MyConfigurationSource/MyConfigurationProvider simply because by the time ConfigurationBuilder.Build is invoked, ServiceCollection.BuildServiceProvider has not been invoked.
A typical workaround would be to create another instance of IServiceProvider with required configuration and use it inside MyConfiguration....
Something like
internal class MyConfigurationProvider : ConfigurationProvider
{
    public MyConfigurationSource Source { get; };
    public MyConfigurationProvider()
    {
        Source = source;
        ServiceProvider = BuildServiceProvider();
    }
    public override void Load()
    {
        // I'd like to assign here my configuration data by using some dependencies
        Data = ServiceProvider.GetRequiredService<IMyService>().GetData();
    }
    
    protected virtual void ConfigureServices(IServiceCollection services)
    {
        services.AddMyService();
        // etc.
    }
    private IServiceProvider BuildServiceProvider()
    {
        var services = new ServiceCollection();
        ConfigureServices(services);
        return services.BuildServiceProvider();
    }
}
but this might not always be appropriate so I would also consider setting the value directly (though I didn't find any official information about how good this approach is)
public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        ...
        app.SetupMyConfiguration();
        ...
    }
}
...
public static class ApplicationBuilderExtensions
{
    public static IApplicationBuilder SetupMyConfiguration(this IApplicationBuilder app)
    {
        var configuration = app
            .ApplicationServices
            .GetRequiredService<IConfiguration>(); // alternatively IOptions<MyOptions>
        var myService = app
            .ApplicationServices
            .GetRequiredService<IMyService>();
        configuration["MyKey"] = myService.GetData("MyKey");
    }
}
UPD. There's also an alternative with using strongly typed options object and IConfigureOptions.
public class MyConfigurationBuilder : IConfigureOptions<MyConfiguration>
{
    private readonly IConfiguration _configuration;
    private readonly IMyService _service;
    public MyConfigurationBuilder(
        IConfiguration configuration,
        IMyService service)
    {
        _configuration = configuration;
        _service = service;
    }
    public void Configure(MyConfiguration myConfiguration)
    {
        // you may set static configuration values
        _configuration
            .GetSection(nameof(MyConfiguration))
            .Bind(myConfiguration);
        // or from DI
        myConfiguration.Data = _service.GetData();
      // here we still can update IConfiguration, 
      // though it doesn't seem to be a good idea
      _configuration["MyKey"] = _service.GetData("MyKey");
    }
}
services.AddSingleton<IConfigureOptions<MyConfiguration>, MyConfigurationBuilder>();
or inject dependencies directly into MyConfiguration
services.Configure<MyConfiguration>(
    serviceProvider =>
        ActivatorUtilities.CreateInstance<MyConfiguration>(serviceProvider, "staticConfigValue"));
public class MyConfiguration
{
    public MyConfiguration(string staticValue, IMyService service)
    {
       ...
    }
}
public class Service
{
    public Service(IOptions<MyConfiguration> options) {}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With