#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; }
}