具有其他依赖项的 ConfigurationProvider

Posted

技术标签:

【中文标题】具有其他依赖项的 ConfigurationProvider【英文标题】:ConfigurationProvider with other dependencies 【发布时间】:2020-09-16 16:40:43 【问题描述】:

我已经实现了我的自定义 IConfigurationProvider 和 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 = .... 
    

我在 Startup 构造函数中构建我的配置(我覆盖了 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();

扩展方法:

public static IConfigurationBuilder AddMyConfiguration(this IConfigurationBuilder builder, string foo)

    return builder.Add(new MyConfigurationSource 
        
            Foo = url
        );

我希望我能以某种方式注入要在Load 方法中使用的服务。这里的问题是配置build是在Startup构造函数中完成的。我只能注入在此构造函数中可用的依赖项:IWebHostEnvironmentIHostEnvironmentIConfiguration 以及我在构建 WebHost 时添加的所有依赖项。当我调用AddMyConfiguration 扩展方法时,也必须传递这些依赖项。我怎么能使用当时甚至不存在的依赖项?

【问题讨论】:

【参考方案1】:

回答有点晚了。

很明显,在MyConfigurationSource/MyConfigurationProvider 中无法使用使用Startup.ConfigureServices 构建的容器,因为在调用ConfigurationBuilder.Build 时,还没有调用ServiceCollection.BuildServiceProvider

典型的解决方法是创建另一个具有所需配置的IServiceProvider 实例并在MyConfiguration... 中使用它。

类似

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();
    

但这可能并不总是合适的,所以我也会考虑直接设置值(虽然我没有找到任何关于这种方法有多好的官方信息)

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");
    


【讨论】:

以上是关于具有其他依赖项的 ConfigurationProvider的主要内容,如果未能解决你的问题,请参考以下文章

在android中创建一个具有依赖项的库

从 CRAN 镜像安装具有依赖项的本地 R 包

具有依赖项的 Maven2 + JMeter + JUnit

具有依赖项的 CocoaPods 框架 - 在框架模块中包含非模块化标头

具有依赖项的 Keycloak 扩展

具有依赖项的 registerModule