2015-02-11 44 views
1

我有一個使用UnitOfWork接口和管理器的項目設置。所有這一切都運行良好,而我只需要使用accountMananger作爲控制器的基礎。Autofac,MVC控制器的動態依賴注入

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

和我的控制器是這樣創建的,並且工作正常。

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

現在我創建其他業務經理和我認識到,在項目結束時我BaseController構造將是巨大的或我將有一個基於控制器我對各種簽名的負荷。如果我忘記了一些事情並需要另一位經理並更改一個構造函數,則所有其他控制器也需要更改。

我的意思是,我實際上總是希望accountManager注入/解決在基地。我可以這樣做嗎?因爲我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 exampleinterception(其中一些DI容器的支持),使用Decorator Pattern,並把依賴於環境的上下文(如HttpContext的。項目)。

我可以看到這成爲一個很大的負擔,創建基於我需要的控制器,我還沒有的構造函數。

這就是爲什麼你應該繼承DefaultControllerFactory,併爲其提供在應用程序啓動(在composition root)的DI容器的一個實例。通常情況下,容器有責任爲您的控制器提供依賴關係,特別是在您的應用程序很大時。

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 2015-02-11 20:08:19

+1

大聲笑 - 我認爲我是'STEROID'上的一個抽象工廠'的經典例子:)未知... – ppumkin 2015-02-11 20:23:49

+1

那麼,授權屬性可以被繼承來做到這一點,但是,對於DI目的,它會更好把它分成一個IAuthorizationFilter和一個沒有任何類似於[在這裏]顯示的行爲的屬性(http://stackoverflow.com/questions/27245220/how-can-i-test-for-the-presence-of-an-行動過濾器與構造函數,參數/ 27470397#27470397)。將每個關注點分離成單獨的服務也是一種最佳實踐 - (更新各種事物,做一些檢查)。它被命名爲AccountManager的事實是一種代碼異味,表明它正在做多件事情(這很糟糕)。 – NightOwl888 2015-02-11 20:46:44