2015-02-11 3 views
1

У меня есть настройка проекта с интерфейсами и менеджерами UnitOfWork. Все это хорошо работает, когда я просто должен был использовать accountManager для базы моего контроллера.Autofac, динамическая зависимость Инъекция для контроллеров MVC

protected BaseController(IAccountManager acctManager) 
    { 
     _accountManager = acctManager; 
    } 

и мои контроллеры созданы так и работают.

public class AccountController : BaseController 
    { 
    public AccountController(IAccountManager accountManager) 
     : base(accountManager) 
    { 
    } 

Теперь я создаю другие менеджер бизнеса, и я понимаю, что к концу проекта моего BaseController конструктор собирается быть огромными или я буду иметь нагрузку различных сигнатур на основе контроллера я на , И если я что-то забыл и нуждался в другом менеджере и менял один конструктор, все остальные контроллеры тоже должны были измениться.

Я имею в виду, я действительно ВСЕГДА хочу, чтобы диспетчер учетных записей вводился/разрешался в базе. Я могу это сделать? Потому что я проверяю 99% на авторизацию.

Я читал о ControllerFactories, но также и кто-то упомянул реализовать IDependancyResolver, но нет примера, который является его предпочтительным способом сделать это.

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

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

Извините. Просто узнайте о DI, и это из хорошего учебника, но, как вы видите, не хватает каких-либо дополнительных объяснений.

ответ

2

Что вы имеете с вашим менеджером аккаунта, называется Cross-Cutting Concern. Существует несколько различных способов обмануть этого кота, но вам не следует вводить одну и ту же зависимость в каждый контроллер.

В общем, лучше избегать наследования, потому что это приведет к жесткой связи между вашими классами. Тесная связь очевидна здесь - что, если вам нужен контроллер, у которого не было IAccountManager в качестве зависимости позже?

В этом конкретном случае в MVC уже есть встроенная слабосвязанная структура авторизации, которую вы можете использовать - AuthorizeAttribute, что является нормальным способом обработки доступа к вашим методам действий с контроллером.

[Authorize] 
public class AccountController : Controller 
{ 
    public AccountController() { . . . } 

    [AllowAnonymous] 
    public ActionResult Register() { . . . } 

    public ActionResult Manage() { . . . } 

    public ActionResult LogOff() { . . . } 
} 

Есть также несколько других вариантов для реализации сквозных проблем - внедрение IActionFilter - see this for a DI friendly example, interception (который некоторые DI поддержки контейнеров), используя Decorator Pattern и кладя зависимости в окружающем контексте (например, HttpContext. Предметы).

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

Вот почему вы должны наследовать DefaultControllerFactory и предоставить ему один экземпляр вашего DI контейнера при запуске приложения (в composition root). Как правило, ответственность контейнера заключается в предоставлении зависимостей вашим контроллерам, особенно если ваше приложение велико.

public class AutofacControllerFactory 
    : DefaultControllerFactory 
{ 
    private readonly IContainer container; 

    public InjectableControllerFactory(IContainer container) 
    { 
     if (container == null) 
      throw new ArgumentNullException("container"); 
     this.container = container; 
    } 

    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) 
    { 
     if (requestContext.HttpContext.Request.Url.ToString().EndsWith("favicon.ico")) 
      return null; 

     return controllerType == null ? 
      base.GetControllerInstance(requestContext, controllerType) : 
      this.container.Resolve(controllerType) as IController; 
    } 
} 

Я настоятельно рекомендую вам прочитать книгу Dependency Injection in .NET. DI является одной из самых непонятных концепций в разработке программного обеспечения, и стоит инвестировать в изучение темы в деталях самостоятельно, без необходимости просеивать дезинформацию в Интернете. Существует много преимуществ, которые можно получить при правильном использовании DI, но неправильное использование часто хуже, чем использование DI вообще.

+0

Благодарим за предоставленную информацию. Мы уже используем атрибут Authorize, но базовый контроллер переопределяет OnAuthroizing, чтобы выполнить некоторые проверки, настроить сеанс, требуя, чтобы accountManager вызывал accountRepo для каждого вызова для обновления различных вещей. Но поскольку вы предлагаете controllerFacotry, который, кажется, предлагается 9/10 раз, мне больше всего нужно разобраться, как это сделать. Я изо всех сил пытаюсь найти реальную выгоду от использования DI, но я действительно хочу понять, что это такое. Спасибо +1 – ppumkin

+1

LOL- Я думаю, что я классический пример «AN ABSTRACT FACTORY ON STEROID» :) Unlearned ... – ppumkin

+1

Ну, авторизованный атрибут можно унаследовать, чтобы сделать именно это, хотя для целей DI было бы лучше разделите его на IAuthorizationFilter и атрибут без какого-либо поведения, аналогичного тому, что показано [здесь] (http://stackoverflow.com/questions/27245220/how-can-i-test-for-the-presence-of-an- действия фильтра с-конструктор-аргументов/27470397 # 27470397). Также лучше всего разделить каждую проблему на отдельную услугу - (обновлять различные вещи, выполнять некоторые проверки). Тот факт, что он называется AccountManager, является запахом кода, который указывает, что он делает больше, чем одно (что плохо). – NightOwl888

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