2017-01-17 32 views
2

Я пытаюсь добавить Ninject к следующей настройке -Как создать базовый класс, который принимает параметры для контроллеров без изменения дочерних контроллеров?

public class BaseController : Controller 
{ 
    protected ILogger Logger {get;} 
    public BaseController() { Logger = new MyLogger(); } 
} 
public class Controller1Controller : BaseController { ... } 
public class Controller2Controller : BaseController { ... } 
.... 
public class ControllerNController : BaseController { ... } 

С Ninject, добавив параметр ILogger к BaseController отлично работает -

public class BaseController : Controller 
{ 
    protected ILogger Logger {get;} 
    public BaseController(ILogger logger) { Logger = logger; } 
} 

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

public class Controller1Controller : BaseController { 
    public Controller1Controller(ILogger logger) : base(logger) { } 
} 

Существует более 50 дочерних контроллеров и d в будущем это может стать проблемой для обслуживания, если нам нужно добавить/удалить больше зависимостей. Кроме того, код, добавляемый к каждому контроллеру, точно такой же.

Есть ли способ держать дочерние контроллеры такими, какие они есть (без каких-либо конструкторов), но все же внести это изменение в BaseController?

+0

Используйте инструмент рефакторинга как [ReSharper] (https://www.jetbrains.com/resharper/). –

+0

Возможный дубликат [Вопросы об использовании Ninject] (http://stackoverflow.com/questions/36221865/questions-about-using-ninject) – NightOwl888

ответ

1

Извините, но нет.

В качестве альтернативного решения можно получить ILogger от Ninject: Using property injection instead of constructor injection

+0

Спасибо. Это решило проблему, но с предостережением о том, что свойства должны быть общедоступными и иметь сеттеры, поэтому он (из того, что я видел в моем тестировании до сих пор) не будет работать с непубличными или readonly свойствами. – Achilles

+0

Если у вас есть доступ к Ninject ядра, то вы можете получить его, как это: 'BaseController общественного класса: контроллер { защищенному ILogger Logger {получить;} общественного BaseController() { \t Logger = Kernel.Get () ; } } ' – tomludd

+0

@tomludd: Это не DI, это местоположение службы. И это своего рода анти-образец. см. http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern – Nauman

1

Простого ответ: Нет (Вы должны обновить свои производные конструкторов класса)

Объяснения: Для введенного экземпляра ILogger быть переданы через производные и базовые классы, вам необходимо обновить полученные конструкторы с параметром ILogger, а затем переместите параметр на базу. Если не существует более разумного решения этой ситуации.

Посмотрите на первую точку в недостатках раздел на вики DI Disadvantages (DI поставляется с этим багажом)

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

Обновление: частично согласен с решением tomludd использования инъекции свойств. См. this SO answer. Для более методов DI, пожалуйста, прочитайте статьи/блоги из Mark Seemann или его книгу DI in .NET

+0

Спасибо. Почему частично согласен с решением tomludd? – Achilles

+0

@Achilles: Потому что, при установке setter/property, вы вынуждены делать инъекционные свойства «public». И в этом случае структура DI диктует эти правила. Кроме того, см. Ссылку в ответе на вопрос SO. Кроме того, решение доступа к ядру в базовом контроллере является своего рода анти-шаблоном, и вы побеждаете цель использования DI. Вы занимаетесь сервисом, см. Это сообщение в блоге: http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/ – Nauman

+0

Спасибо, теперь имеет смысл. Спасибо за информативные ссылки. – Achilles

0

Try это в BaseController конструктор

public BaseController(ILogger logger = null) 
{ 
    if (logger != null) 
     Logger = logger; 
    else 
     Logger = new MyLogger(); 
} 
+0

Это не решает основной проблемы. – Achilles