Получение IConfiguration из 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 в качестве параметра метода.


person Jehof    schedule 18.08.2017    source источник
comment
Явные зависимости следует вводить непосредственно там, где они необходимы. В противном случае код будет вводить в заблуждение. Хотя, как сказано, не то, что вы хотели, было бы лучше, если бы вы ввели его непосредственно в метод.   -  person Nkosi    schedule 18.08.2017
comment
Имхо, это плохой дизайн для доступа к IConfiguration из любого места, кроме корня композиции (класс Startup для ядра ASP.NET), поскольку это подразумевает, что файл конфигурации должен иметь определенную структуру, которую вообще нельзя изменить. Вместо этого я бы написал метод расширения для настройки классов конфигурации внутри корня композиции и передачи объекта IConfiguration, аналогично тому, как .Configure<MyLibConfig>(Configuration.GetSection("MyLibConfig"). Таким образом, разработчик, составляющий свое приложение из ваших компонентов, может решить, где разместить его в файле appsettings.json.   -  person Tseng    schedule 18.08.2017
comment
Или как бы вы разрешили конфликты, когда две библиотеки напрямую ссылаются на IConfiguration и имеют один и тот же раздел в конфигурации? то есть JsonSettings, но имеют совершенно другую структуру? Это можно решить, только позволив разработчику, составившему его, выбрать и передать имя раздела вашему методу расширения, который устанавливает параметры через .Configure<T>   -  person Tseng    schedule 18.08.2017
comment
У меня не сработало, так как ImplementationInstance было нулевым. Пришлось звонить .ImplementationFactory(null). Работает, но грязновато конечно.   -  person PhillipM    schedule 15.12.2020


Ответы (3)


Согласно комментариям, я изменил свой метод расширения на следующий, так что компоновщик приложения должен предоставить раздел конфигурации для моих параметров.

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

Решение использовать его таким образом в основном связано с этими комментариями. Этот способ может быть более уместным при разработке компонентов, которые используются многими разработчиками, чем для внутреннего компонента, который вы используете в своем приложении.

Имхо, это плохой дизайн для доступа к IConfiguration из любого места, кроме корня композиции (класс Startup для ядра ASP.NET), поскольку это подразумевает, что файл конфигурации должен иметь определенную структуру, которую вообще нельзя изменить. Вместо этого я бы написал метод расширения для настройки классов конфигурации внутри корня композиции и передачи объекта IConfiguration, аналогично тому, как .Configure(Configuration.GetSection("MyLibConfi‌​g"). Таким образом, разработчик, составляющий свое приложение, из ваших компонентов может решить, где разместить его в appsettings.json

Или как бы вы разрешили конфликты, когда две библиотеки напрямую ссылаются на IConfiguration и имеют один и тот же раздел в конфигурации? то есть JsonSettings, но имеют совершенно другую структуру? Это можно решить, только позволив разработчику, составившему его, выбрать и передать имя раздела вашему методу расширения, который устанавливает параметры через .Configure.

person Jehof    schedule 21.08.2017

Чтобы получить IConfiguration из IServiceCollection, почему бы просто не разрешить зависимость?:

IConfiguration configuration = services.BuildServiceProvider().GetService<IConfiguration>();
person bytedev    schedule 18.06.2020
comment
Потому что это требует создания поставщика услуг. - person Alexander Trauzzi; 30.11.2020
comment
В зависимости от типа приложения и того, что вы делаете, это может не иметь большого значения. - person bytedev; 16.12.2020

Я создал свой собственный тип «коллекции сервисов», который обернул IServiceCollection и IConfiguration, и все мои модули используют этот тип для регистрации своих сервисов. Например:

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, поиск его в наборе сервисов снова и снова может оказаться немного утомительным.

person Henk Mollema    schedule 18.08.2017