0

Я использую MVC 3. Предположим, у меня есть базовый контроллер и несколько производных контроллеров. Я использую IoC и мой базовый конструктор контроллер выглядит следующим образом:MVC3 с IoC: слишком много параметров в базовом контроллере. Любая альтернатива?

private readonly ICacheProvider _cacheProvider; 
private readonly ILoggerProvider _loggerProvider 
private readonly IAuditProvider _auditProvider 
public abstract class MyControllerBase : Controller 
{ 
    protected MyControllerBase(ICacheProvider cacheProvider, ILoggerProvider loggerProvider, IAuditProvider auditProvider, ...) 
    { 
    _cacheProvider = cacheProvider; 
    _loggerProvider = loggerProvider; 
    _auditProvider = auditProvider; 
    ... 
    } 
} 

До сих пор так хорошо? Может быть. Однако каждый из моих полученных контроллеров необходимо определить конструктор, который соответствует конструктор подписи базового класса, например:

public class MyDerivedController1 : MyControllerBase 
{ 
     public MyDerivedController1(ICacheProvider cacheProvider, ILoggerProvider loggerProvider, IAuditProvider auditProvider, ...) 
     : base(cacheProvider, loggerProvider, auditProvider, ...) 
    { } 
} 

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

Я думал, что я хотел бы создать ServiceProvider (или Услугу Локатор?) Класс (и интерфейс IServiceProvider), который будет иметь конструктор и все провайдер в качестве параметров (где IoC будет выполнять свою работу) и выставить их в качестве свойств. Тогда мой базовый конструктор и производные конструкторы будут иметь только IServiceProvider в качестве параметра.

Однако я обеспокоен тем, что этот подход будет иметь некоторые отрицательные воздействия, например: 1- Скрытая реализация: я не знаю, какой провайдер я использую или нуждаюсь, если не проверю реализацию. 2- Трудно проверить: когда конструктор содержит параметры, я могу легко его протестировать, и я знаю, чего ожидать (автоматически задокументировано).

Есть ли у кого-нибудь предложения или комментарии?

+1

Что именно делает «MyControllerBase»? Будет ли образец декоратора альтернативой? –

+0

@ Daniel, MyControllerBase содержит несколько вспомогательных методов (как-то расширяя базовый класс контроллера MVC), содержит настраиваемый атрибут Authorize и другие атрибуты и другие методы, используемые для входа в пользовательские данные, проверьте, должна ли отображаться страница условий и условий и т. Д. – AndreCruz

+0

Это сообщение в блоге мне немного помогло, но оно применяется только тогда, когда вы можете собрать общее поведение или группу более одного провайдера вместе. Что, если в моем случае у меня есть 5 или более поставщиков, которые мне нужны в моем Контролере с совершенно разными обязанностями? http://blog.ploeh.dk/2010/02/02/RefactoringtoAggregateServices/ – AndreCruz

ответ

0

После некоторых исследований я не смог найти хорошее решение. Как упоминал Даниэль Хильгарт, у контроллера слишком много зависимостей, которые нарушают SRP. Согласен. Учитывая, что это существующее приложение, я не могу реорганизовать и перепроектировать все это. Например, я хотел бы перемещать зависимости, такие как ICacheProvider, ILoggerProvider и IAuditProvider, на другой уровень, который будет отвечать за извлечение данных из репозитория.

Я не хочу начинать обсуждение здесь, но мне не нравится идея ссылки на Entity Framework в моем веб-проекте MVC. Я бы предпочел создать уровень доступа к данным и полностью удалить ссылки на EF. Итак, вернемся к моей проблеме, у меня есть базовый контроллер с зависимостями X, и всем производным контроллерам нужен конструктор со всеми этими ссылками (как объяснялось в моем вопросе выше).

Я рассмотрел несколько вариантов:

1) с помощью Service Locator. Прочитав несколько сообщений, я решил проигнорировать этот вариант.

Is it bad to use servicelocation instead of constructor injection to avoid writing loads of factory classes

IoC.Resolve vs Constructor Injection

http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/

2) Использование агрегатных услуги. Это хорошая идея, но я не мог группировать свои зависимости, и я тоже решил проигнорировать это.

How to avoid Dependency Injection constructor madness?

http://blog.ploeh.dk/2010/02/02/RefactoringtoAggregateServices/

3) Создание нового поставщика, которое обнажает всю другую зависимость, как свойства. Я не вполне доволен этой опцией, потому что она каким-то образом скрывает детали реализации. Но после всех соображений я решил его реализовать. Найдите ниже нового интерфейса и класса, созданный:

public interface IMyControllerProvider 
    { 
    ICacheProvider CacheProvider { get; } 

    ILoggerProvider LoggerProvider { get; } 

    IAuditProvider AuditProvider { get; } 

    ... 
    } 


    public class MyControllerProvider : IMyControllerProvider 
    { 
    private readonly ICacheProvider _cacheProvider; 
    private readonly ILoggerProvider _loggerProvider; 
    private readonly IAuditProvider _auditProvider; 
    ..... 

    public MyControllerProvider(ICacheProvider cacheProvider, ILoggerProvider loggerProvider, IAuditProvider auditProvider, ...) 
    { 
     _cacheProvider = cacheProvider; 
     _loggerProvider = loggerProvider; 
     _auditProvider = auditProvider; 
     ... 
    } 

    public ICacheProvider CacheProvider { get { return _context; } } 
    public ILoggerProvider LoggerProvider { get { return _context; } } 
    public IAuditProvider AuditProvider { get { return _context; } } 
} 

После этого я переработан моя база контроллер и все производные контроллеры использовать IMyControllerProvider вместо. Он отлично работает, потому что:

1- Производные контроллеры теперь имеют конструктор с одной зависимостью.

2- Хотя новая зависимость IMyControllerProvider «скрывает» реальная зависимость, при проверке регулятора по-прежнему легко понять, что существует и другая зависимость (в конструкторе документы, которые).

private readonly ICacheProvider _cacheProvider; 
private readonly ILoggerProvider _loggerProvider 
private readonly IAuditProvider _auditProvider 
public abstract class MyControllerBase : Controller 
{ 
    protected MyControllerBase(IMyControllerProvider myControllerProvider) 
    { 
     _cacheProvider = myControllerProvider.CacheProvider; 
     _loggerProvider = myControllerProvider.LoggerProvider; 
     _auditProvider = myControllerProvider.AuditProvider; 
    } 
} 

public class MyDerivedController1 : MyControllerBase 
{ 
     public MyDerivedController1(IMyControllerProvider myControllerProvider) 
      : base(myControllerProvider) 
    { } 
} 

Не лучшее решение, но единственное, что я мог придумать, учитывая ограничение рефакторинга всего приложения.

Смежные вопросы