DI и базовый класс

#c# #inheritance #asp.net-core #dependency-injection

#c# #наследование #asp.net-core #внедрение зависимостей

Вопрос:

Я создал простой asp.net основное приложение на типичном примере, и оно работает так, как ожидалось. Затем я добавил поддержку конфигурации через appsettings.json следующим образом:

 [ApiController]
[Route("[controller]/[action]")]
public class MyController: BaseController
{
private IConfiguration _configuration = null;
public MyController(IConfiguration configuration)
        {
            _configuration = configuration;
        }
//some actions here
}
  

и это тоже сработало.
Но теперь я хотел иметь реализацию Configuration в моем базовом классе ( BaseController ), чтобы все производные контроллеры имели к нему доступ.

Ничего сложного, подумал я и переписал это:
открытый класс

 [ApiController]
[Route("[controller]/[action]")]
public class MyController: BaseController
{
//some actions here
}

public class BaseController: ControllerBase
{
        private IConfiguration _configuration = null;
        public IConfiguration Configuration
        {
            get
            {
                return _configuration;
            }
        }

        public BaseController(IConfiguration configuration = null)
        {
            _configuration = configuration;
        }
}
  

и хотя этот код успешно компилируется со значением параметра по умолчанию в конструкторе базового класса, Configuration всегда null .

Что я делаю не так и может ли это теперь заставить это работать чистым способом?

Комментарии:

1. Вы не должны вводить IConfiguration в первую очередь. Вместо этого используйте IOptions<T> шаблон

2. В любом случае вопрос остается тем же: как инициализировать DI-ресурс в базовом классе, ничего не затрагивая в производном? Все решения, приведенные ниже, фактически игнорируют инициализацию в базовом классе и требуют изменений в производном.

3. Вы не можете, это точка внедрения конструктора (только один поддерживается платформой IoC по умолчанию). Вы вводите классы Ioptions в конкретные контроллеры и используете только общие параметры в базовых классах. Ваш дизайн кажется ошибочным, чтобы вводить общую конфигурацию, когда каждому контроллеру нужна своя

4. кстати. Внедрение конструктора диктует обязательные зависимости, как в «без этого класс не будет / не может работать». Таким образом, все, что вы вводите в него, абсолютно необходимо . И если вашему базовому классу не нужны какие-либо конкретные (общие) параметры, то не вводите его туда, поскольку это явно не требуется. И если это общая опция, которая абсолютно необходима даже базовому классу и каждому производному классу, то ее также необходимо определить в конструкторе (поскольку она обязательна)

5. Кроме того, внедрение зависимостей (или, точнее, контейнера DI / IoC) не является черной магией компилятора, все, что он делает, — это то, что вы обычно делаете при new редактировании класса, за исключением того, что фреймворк IoC / DI берет на себя работу по инициализации, передаче и управлению временем жизни зависимостей

Ответ №1:

Вам нужно передать IConfiguration параметр из конструктора подкласса в конструктор базового класса.

Пример:

 public abstract class BaseClass
{
    protected IConfiguration _configuration;

    public BaseClass(IConfiguration configuration)
    {
        _configuration = configuration;
    }
}
  

Обратите внимание, что переменная экземпляра IConfiguration базового класса должна быть защищена, если вы хотите иметь доступ к ней из подкласса.

 public class SubClass : BaseClass
{
    public SubClass(IConfiguration configuration) : base(configuration) { }
}
  

Добавляя base(configuration) , вы вызываете конструктор базового класса и передаете ему configuration параметр.

Ответ №2:

Прежде всего. Отметьте свой базовый класс abstract с помощью protected конструктора. Используйте base ключевое слово из вашего дочернего класса, чтобы создать экземпляр конфигурации значка частного поля в вашем базовом классе.

    public class MyController(IConfiguration configuration) : base(configuration) {}

    public abstract class BaseClass
    {
       protected BaseClass(IConfiguration configuration) { _configuration = configuration; }
    }