2010-10-11 211 views
6

以下代碼僅用於演示目的。Castle Windsor IOC:將構造函數參數傳遞給子組件

假設我有2個組件(businessService和dataService)和一個UI類。

UI類需要一個業務服務,businessService需要一個dataService,而dataService需要一個connectionString。

形式的UI類,我需要解決的業務服務,所以我寫了下面的代碼:

var service = container.Resolve<BusinessService>(new { dependancy = "con string 123" })); 

通知,扶養是的connectionString構造函數的參數。

但上面的代碼不起作用,說dataService期待依賴性,這是不合格的。

無法創建組件「的DataService」 因爲它依賴是 滿意。 dataService正在等待 以下相關性:

鍵(具有特定鍵的組件) - 未註冊的依賴性。

因此,作爲一種解決辦法我這樣做:

var service = container.Resolve<BusinessService>(new { dataService = container.Resolve<IDataService>(new { dependancy = "123" }) }); 

但是從設計,編碼風格和許多觀點,這是不這樣做的一個很好的方式。

所以,如果你能告訴爲什麼它不以簡單的方式工作,或者你有更好的解決方法,請分享。

+0

能否請您提供的BusinessService,DataService的一個簡短而完整的定義,和扶養/的connectionString會失敗?刪除不直接有助於重現問題的任何代碼。 – 2010-10-11 09:30:53

+0

它的簡單和直接的 – 2010-10-11 10:46:53

+0

公共類的BusinessService {公衆的BusinessService(DataService的DataService的){}} – 2010-10-11 10:48:23

回答

6

您看到的行爲是通過設計。

有幾種方法可以解決這個問題,具體取決於您希望傳遞的值的動態方式。

The documentation做了一個很好的工作細節,所以我不會在這裏重申。

更新

要清晰 - 溫莎沒有通過內嵌參數下的解析管道。原因很簡單 - 這樣做會打破抽象。調用代碼必須隱式知道您的BusinessService取決於DataService,這取決於連接字符串。

如果你絕對必須這樣做,比做明確。這與你正在做的幾乎相同 - 解決DataService顯式依賴於連接字符串,並明確解決BusinessService傳遞DataService作爲依賴關係。

爲了讓事情真正明確(和更好的使用爲好)我會使用類型化的工廠,瞭解建議而不是直接調用容器

public interface IFactory 
{ 
    IDataService ResolveDataService(string connectionString); 
    IBussinessService ResolveBussinessService(IDataService dataService); 
    // possibly release method for IBussinessService as well 
} 
+0

檢查你的鏈接,但嚴重我無法理解他們在說西隧,我們可以char或sthng有簡單的答案 – 2010-10-11 11:08:11

+0

@moutasema我簡單的問題是,當我解決父組件 - 但是爲它的孩子發送參數時,它會起作用嗎? @moutasema容器能否自動將參數傳遞給子組件? @kkozmic沒有,內嵌參數不向下傳播的解析管道 – 2010-10-11 11:18:01

+2

@Moutasem AL-AWA:簡而言之,你試圖做一些事情,在99%的情況是不好的做法。避免直接調用'Resolve()'(因爲你正在做服務位置而不是依賴注入),你會看到正確的方法來做到這一點。 – 2010-10-11 13:39:54

1

我也需要創建瞬態組件時,可以做到這一點需要一個上下文對象。我使用的解決方案是覆蓋DefaultDependencyResolver類,以便它沿着分辨率管道傳遞內聯參數。需要

public class ArgumentPassingDependencyResolver : DefaultDependencyResolver 
{ 
    protected override CreationContext RebuildContextForParameter(
     CreationContext current, Type parameterType) 
    { 
     if (parameterType.ContainsGenericParameters) 
     { 
      // this behaviour copied from base class 
      return current; 
     } 

     // the difference in the following line is that "true" is passed 
     // instead of "false" as the third parameter 
     return new CreationContext(parameterType, current, true); 
    } 
} 

這個類的一個實例的容器被創建時的傳遞(其他類也需要,因爲沒有便利的構造函數,只需要依賴解析器將傳入):

var container = new WindsorContainer(
    new DefaultKernel(
     new ArgumentPassingDependencyResolver(), 
     new NotSupportedProxyFactory()), 
    new DefaultComponentInstaller()); 
0

是的,你所要求的是可能的,但你應該通過Typed Factory Facility使用抽象工廠,而不是通過容器直接請求你的服務。

有類型的工廠,所有你需要做的是定義工廠接口和溫莎會照顧執行的爲您服務。

public interface IBusinessServiceFactory { 
    IBusinessService CreateBusinessService(string connString); 
} 

public interface IDataServiceFactory { 
    IDataService CreateDataService(string connString); 
} 

您添加設備,並註冊您的工廠界面如下:

container.AddFacility<TypedFactoryFacility>(); 
container.Register(Component.For<IDataServiceFactory>().AsFactory()); 
container.Register(Component.For<IBusinessServiceFactory>().AsFactory()); 

你現在可以手動定義如何運行時參數會在你的BusinessService註冊定義Dynamic Parameter傳下來的對象圖。

container.Register(Component.For<IBusinessService, BusinessService>() 
    .LifestyleTransient() 
    .DynamicParameters((k, d) => { 
     d["dataService"] = k.Resolve<IDataServiceFactory>.CreateDataService((string)d["connString"]); 
    })); 

記住字典鍵必須在CreateBusinessService方法和BusinessService構造相匹配的參數名稱。

你也應該讓LifestyleTransient如果你打算給每個工廠方法被調用時創建一個新的實例。 (默認值是單身)

相關問題