2012-12-09 51 views
1

我們有一個MVC3控制器,其中有一些'常見'工作,我們將其放入控制器構造函數中。一些常見的工作是通過一個可以通過Unity動態解析(用於IoC /依賴注入)的失敗耦合類(例如ourService)完成的。 ourService在Controller的構造函數中爲空(即未解析),但在正常的Controller方法中正確解析。下面這個簡單的演示代碼顯示問題:Unity不解決MVC3控制器構造函數中的依賴關係

public class Testing123Controller : BaseController 
{ 
    [Dependency] 
    public IOurService ourService { get; set; } 

    public Testing123Controller() 
    { 
      ourService.SomeWork(1); // ourService=null here !! 
      ... 
    } 

    public ActionResult Index() 
    { 
      ourService.SomeWork(1); // resolved properly here here !! 
      ... 
    } 
    ... 
} 

問題

  1. 爲什麼會出現在Unity解析行爲有何不同?我會期待一致的行爲。
  2. 我該如何解決這個問題,即使在控制器的構造器中,Unity也解決了這個問題?

的方式,我們已經建立統一2.0:

的Global.asax

Application_Start() 
{ 
    ... 
    Container = new UnityContainer(); 
    UnityBootstrapper.ConfigureContainer(Container); 
    DependencyResolver.SetResolver(new UnityDependencyResolver(Container)); 
    ... 
} 

public static void ConfigureContainer(UnityContainer container) 
{ 
    ... 
    container.RegisterType<IOurService, OurService>(); 
    ... 
} 

IOurService.cs

public interface IOurService 
{ 
    bool SomeWork(int anInt); 
} 

OurService.cs

public class OurService: IOurService 
{ 
    public bool SomeWork(int anInt) 
    { 
     return ++anInt; //Whew! Time for a break ... 
    } 
} 
+0

好閱讀這裏:http://www.fascinatedwithsoftware.com/blog/post/2012/02/01/Prefer-Constructor-Injection-Over-Property-Injection.aspx這裏有一個很好的解釋:http:// stackoverflow.com/questions/11125883/property-dependency-injection-used-in-constructor-using-unity – timothyclifford

回答

5

作爲類的基本原理,在可以設置實例屬性之前,必須實例化實例。

Unity需要設置依賴項屬性,但它不能這樣做,直到實例完全實例化 - 即構造函數必須完成執行。

如果您在構造函數中引用了依賴項屬性,那麼這就太早了 - Unity沒有辦法設置它 - 因此它將被取消設置(即null)。

如果您需要在構造函數中使用依賴項,那麼您的必須使用構造函數注入。雖然在一般情況下,使用構造器注入通常是無論如何更好的方法:

public class Testing123Controller : BaseController 
{ 
    public IOurService ourService { get; set; } 

    public Testing123Controller(IOurService ourService) 
    { 
      this.ourService = ourService; 
      this.ourService.SomeWork(1); // ourService no longer null here 
      ... 
    } 

    public ActionResult Index() 
    { 
      ourService.SomeWork(1); // also resolved properly here 
      ... 
    } 
    ... 
} 

注意:在這個例子中我的情況下,離開ourService作爲一個公共gettable &設置屬性您的代碼的其他部分需要訪問它。另一方面,如果它只能在類中訪問(並且只是爲了Unity的目的而公開),那麼隨着構造器注入的引入,最好將其設置爲private readonly字段。

+0

你能解釋一下爲什麼它應該是一個'field'('private readonly IOurService ourService;')而不是'property'('public IOurService ourService {get;}')?大多數文檔(MSDN,論壇)都建議使用字段。同意他們應該被隔離的概念('{get; set;}'是'public'是另一個dev的代碼) – DeepSpace101

+0

它真的取決於用法。如果需要公開訪問並公開設置,則使用公共「獲取」和「設置」訪問器的公共屬性。如果需要公開訪問但只能私人設置,則使用公共「獲取」的公共財產,但使用私人「集合」。如果不應該公開訪問並需要在類中操作(即設置,讀取,更新),請使用私有(非只讀)字段。如果不應該公開訪問並且只需要私人閱讀(在初始設置之後),則使用專用只讀字段。 –

+0

但Unity的'[Dependency]'裝飾在字段上無效,它需要屬性,索引器或參數。如果屬性,那麼你必須{get; set;},所以我們可以在同一個類的構造函數中設置它 - 只要你的答案。所以我把它改成私有{get; set;} – DeepSpace101

1

您正在使用屬性注入(通過使用Dependency屬性)而不是構造函數注入,因此只有在控制器實例化之後才解析依賴項。如果你想訪問的依賴是構造函數,只需將其添加到構造函數:

private readonly IOurService _ourService { get; set; } 

public Testing123Controller(IOurService ourService) 
{ 
    _ourService = ourService; 
    _ourService.SomeWork(1); // ourService=null here !! 
    ... 
} 
+0

誰會設置傳遞給控制器​​構造函數的'ourService'? AFAIK,無參數控制器構造函數是從外部MVC框架調用的第一個用戶代碼。 – DeepSpace101

+0

如果您的UnityDependencyResolver工作正常(您可能會比使用Unity.Mvc3 NuGet包做得更糟),那麼當框架試圖實例化控制器時,它將確定爲了實例化它,需要實現IOurService 。如果IOurService的實現註冊到Unity,它將實例化它,然後用它來實例化控制器。 –

0

恐怕團結對構造工作,例如本身必須使用Unity解決。 Service構造函數中的Service屬性爲null的事實支持此構想。如果你自己調用控制器(不適用於Unity),Unity沒有時間解決該屬性。

相關問題