【问题标题】:Getting IConfiguration from ServiceCollection从 ServiceCollection 获取 IConfiguration
【发布时间】:2018-01-26 19:23:15
【问题描述】:

我正在为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 实例作为参数添加到方法中。

【问题讨论】:

  • 显式依赖应该直接注入到需要的地方。否则会使代码产生误导。不过,如前所述,如果您将其直接注入方法中会更好。
  • 恕我直言,从组合根内部(ASP.NET 核心的Startup 类)以外的任何地方访问IConfiguration 是一个糟糕的设计,因为这意味着配置文件必须具有特定的结构根本无法改变。相反,我会编写一个扩展方法来配置组合根内的配置类并将IConfiguration 对象传递给,类似于.Configure&lt;MyLibConfig&gt;(Configuration.GetSection("MyLibConfig")。这样,从您的组件组成他的应用程序的开发人员可以决定将其放置在 appsettings.json 中的哪个位置
  • 或者,当两个库直接引用IConfiguration 并且在配置中具有相同的部分时,您将如何解决冲突?即JsonSettings,但结构完全不同?它只能通过让编写它的开发人员选择并将部分名称传递给您的扩展方法来解决,该方法通过.Configure&lt;T&gt;设置选项
  • 对我不起作用,因为 ImplementationInstance 为空。不得不打电话给.ImplementationFactory(null)。工作,但当然很脏。

标签: c# asp.net-core asp.net-core-2.0 asp.net-core-configuration


【解决方案1】:

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

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

来自 StartUp 类,调用看起来像

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

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

恕我直言,从任何地方访问 IConfiguration 都是一个糟糕的设计,除了 在组合根(ASP.NET 核心的启动类)内,就像这样 意味着配置文件必须具有特定的结构 根本无法改变。相反,我会写一个扩展方法 配置组合根内的配置类并传递 IConfiguration 对象,类似于如何 .Configure(Configuration.GetSection("MyLibConfi‌​g"). 这样,从您的应用程序中编写应用程序的开发人员 组件可以决定在 appsettings.json 中放置它的位置

或者当两个库直接发生冲突时,你将如何解决 引用 IConfiguration 并在 配置?即 JsonSettings 但结构完全不同?它 只能通过让编写它的开发人员选择和解决 将部分名称传递给您的扩展方法,该方法设置 通过 .Configure 选项

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • 因为这需要构建服务提供者。
    • 取决于应用程序的类型以及您在做什么,这可能根本不是什么大问题。
    • 您将如何获得服务?
    【解决方案3】:

    我创建了自己的“服务集合”类型,它包装了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 实例,您可能会发现在服务集合中一遍又一遍地搜索它有点乏味。

    【讨论】:

    • 我想知道是否有人要解决这个选项。我个人会以更流畅的方式编写api,即services.WithConfiguration(Configuration).AddServiceA().AddServiceB();,但想法是一样的。
    猜你喜欢
    • 2021-11-01
    • 2022-01-27
    • 2022-10-07
    • 2017-05-10
    • 2019-05-03
    • 2023-02-02
    • 2020-08-27
    • 2018-06-09
    相关资源
    最近更新 更多