从 ServiceCollection 获取 IConfiguration

Getting IConfiguration from ServiceCollection

我正在为 ServiceCollection 编写自己的扩展方法来注册我的模块类型,我需要访问集合中的 IConfiguration 实例来注册我的选项。

扩展方法

public static IServiceCollection AddApi(this IServiceCollection services)
{
  // Get configuration from collection
  var configuration = (IConfiguration) services.FirstOrDefault(p => p.ServiceType == typeof(IConfiguration)).ImplementationInstance;

  services.Configure<DatabaseOptions>(configuration.GetSection("Database"));
}

这是从集合中获取 IConfiguration 实例的正确方法还是有更优雅的解决方案?我不想将 IConfiguration 实例作为参数添加到方法中。

我创建了自己的 "service collection" 类型,它包装了 IServiceCollectionIConfiguration 并且我的所有模块都使用该类型来注册它们的服务。例如:

public interface IMyServiceCollection
{
    public IServiceCollection Services { get; set; }

    public IConfiguration Configuration { get; set; }
}

public static void AddFooModule(this IMyServiceCollection myServices)
{
    var services = myServices.Services;
    var config = myServices.Configuration;
}

然后你必须创建一个以配置实例为参数的扩展方法,它为 IMyServiceCollection 创建实现,例如:

public static IMyServiceCollection CreateServiceCollection(this IServiceCollection services, IConfiguration config)
{
    return new MyServiceCollection 
    { 
        Services = services,
        Configuration = config
    };
}

请注意,我们在模块化框架中使用它。对于简单的应用程序,这是矫枉过正。

我认为你的解决方案也很好。但是,如果您需要经常访问 IConfiguration 实例,您可能会发现在服务集合中一遍又一遍地搜索它有点乏味。

根据评论,我已将我的扩展方法更改为以下内容,以便应用程序的编写者为我的选项提供配置部分。

public static IServiceCollection AddApi(this IServiceCollection services, IConfiguration databaseConfiguration)
{  
  services.Configure<DatabaseOptions>(databaseConfiguration);
}

从 StartUp class 开始,调用看起来像

public void ConfigureServices(IServiceCollection services)
{
  services.AddApi(Configuration.GetSection("Database"));
  services.AddMvc();
}

以这种方式使用它的决定主要是由这些评论决定的。在开发由许多开发人员使用的组件时,这种方式可能比您在应用程序中使用的内部组件更相关。

Imho it's a bad design to access IConfiguration from anywhere except inside the composition root (Startup class for ASP.NET core), as this implies that the configuration file must have a specific structure which can't be changed at all. Instead, I'd write an extension method to configure the config classes inside the composition root and pass a IConfiguration object to, similar to how .Configure(Configuration.GetSection("MyLibConfi‌​g"). This way the developer who composes his application from your components can decide where to place it within the appsettings.json

Or how would you solve conflicts, when two libraries directly reference the IConfiguration and have the same section within the config? i.e. JsonSettings but have completely different structure? It can only be solved by letting the developer who compose it choose and pass the section name to the your extension method which sets up the options via .Configure

要从 IServiceCollection 获取 IConfiguration 为什么不直接解决依赖关系?:

IConfiguration configuration = services.BuildServiceProvider().GetService<IConfiguration>();