2017-06-08 150 views
1

請注意,我已更改問題中的代碼。使用Castle Windsor在服務類的構造函數中初始化具有參數化構造函數的類

請參閱下面的服務器端代碼(WCF服務):

using System.ServiceModel; 
using System.ServiceModel.Web; 
using System.Text; 

using Castle.MicroKernel.Registration; 
using Castle.MicroKernel.SubSystems.Configuration; 
using Castle.Windsor; 


namespace WcfService1 
{ 
    public class WindsorInstaller : IWindsorInstaller 
    { 
     public void Install(IWindsorContainer container, IConfigurationStore store) 
     { 
      container.Register(
       Component.For<IGreeting, Greeting>(), 
       Component.For<IGreetingService, GreetingService>()); 
     } 
    } 

    public interface ILanguage 
    { 
     string SayHello(); 
    } 

    public class Spanish : ILanguage 
    { 
     public string SayHello() 
     { 
      return "Hola"; 
     } 
    } 

    public interface IGreeting 
    { 
     string SayHello(); 
    } 

    public class Greeting: IGreeting 
    { 
     ILanguage Language; 

     public Greeting (ILanguage language) 
     { 
      Language = language; 
     } 

     public string SayHello() 
     { 
      return Language.SayHello(); 
     } 
    } 

    public interface IGreetingFactory 
    { 
     IGreeting Create(ILanguage Language); 
    } 

    [ServiceContract] 
    public interface IGreetingService 
    { 
     [OperationContract] 
     string SayHello(string strLanguage); 
    } 

    public class GreetingService : IGreetingService 
    { 
     private readonly IGreetingFactory greetingFactory; 
     private IGreeting greeting; 

     public GreetingService() 
     { 
     } 

     public GreetingService(IGreetingFactory greetingFactory) 
     { 
      // store the factory until we need it 
      this.greetingFactory = greetingFactory; 
     } 

     public string SayHello (string strLanguage) 
     { 
      if (strLanguage == "S") 
      { 
       ILanguage Language = new Spanish(); 
       Language = new Spanish(); 
       greeting = new Greeting(Language); 
      } 
      return greeting.SayHello(); 
     } 

    } 
} 

和下面的客戶端代碼:

ServiceReference1.GreetingServiceClient s1 = new ServiceReference1.GreetingServiceClient(); 
      string greeting = s1.SayHello("S"); 

ServiceReference1.GreetingServiceClient是一個服務引用。

代碼的工作原理與我所期望的一樣,即Castle Windsor允許我在服務的構造函數中注入Greeting。然而,Greeting類本身有一個參數化的構造函數(它需要一個語言)。在上面的代碼中,我必須在服務的Say Hello方法中初始化Greeting(使用語言)。如何在服務的構造函數中初始化Greeting(使用語言)?

+0

是'operator'不是關鍵字(例如:應該是'@ operator'代替)。對於其他事情,我想我寧願依賴包含用戶輸入並使用該引用的對象 – Icepickle

+0

[Castle Windsor註冊類與構造函數參數]的可能重複(https://stackoverflow.com/questions/20243543/castle -windsor-register-class-with-constructor-parameters) – Icepickle

+0

@Icepickle,抱歉,我不知道你的意思。你能發表一個答案嗎? – w0051977

回答

0

提供運行時,用戶驅動或其他動態依賴關係的一種主要方法是使用factories來創建對象。溫莎城堡提供了幾種不同的設施來幫助實現這一目標,或者您可以自己使用內核並實施工廠。

溫莎的工廠允許您提供delegate-based工廠,這些工廠只是創建對象的方法。你可以在這裏使用它,但是你可以創建一些靈活的東西(如果你想將ICalculator的實現替換爲其他類,你必須更新這個方法)。

爲了獲得最大的靈活性,您需要使用Windsor的interface-based工廠。通過這些,你提供了一個工廠的界面,然後Windsor將自動生成一個實現。

讓我們以上面的代碼的簡化版本爲例。如果你剛剛有這樣的對象:

public class Calculator : ICalculator 
{ 
    string Operator; 

    public Calculator(string operator) 
    { 
     Operator=operator; 
    } 
} 

你想通過operator當您創建的對象,你會定義一個工廠,像這樣:

public interface ICalculatorFactory 
{ 
    ICalculator Create(string operator); 
} 

然後,你就註冊在您的安裝:

kernel.Register(Component.For<ICalulatorFactory>().AsFactory()); 

現在,任何你想用一個計算器,你會注入一個工廠,然後只調用Create

public class CalculatorUseExample 
{ 
    private readonly ICalculator addCalculator; 
    private readonly ICalculator subCalculator; 

    public CalculatorUseExample(ICalculatorFactory calculatorFactory) 
    { 
     addCalculator = calculatorFactory.Create("+"); 
     subCalculator = calculatorFactory.Create("-"); 
    } 
} 

請注意,operator參數的名稱很重要;默認情況下(如果需要,可以更改),Windsor按名稱匹配參數。

如果再加上你的CalculatorService類回到組合,你可以使用相同的模式:

public interface ICalculatorServiceFactory 
{ 
    ICalculatorService Create(string operator); 
} 

public class CalculatorService : ICalculatorService 
{ 
    private readonly ICalculator Calculator; 

    public CalculatorService(string operator, ICalculatorFactory calculatorFactory) 
    { 
     Calculator=calculatorFactory.Create(operator); 
    } 
} 

但我真的不喜歡因爲爲什麼要照顧服務運營商是什麼?這是計算器的細節。相反,改變出廠只接受ICalculator,並在那裏你創建這個服務對象組成在一起:

public interface ICalculatorServiceFactory 
{ 
    ICalculatorService Create(ICalculator calculator); 
} 

public class CalculatorService : ICalculatorService 
{ 
    private readonly ICalculator Calculator; 

    public CalculatorService(ICalculator calculator) 
    { 
     Calculator=calculator; 
    } 
} 

public class CalculatorServiceUseExample 
{ 
    public CalculatorServiceUseExample(ICalculatorServiceFactory calculatorServiceFactory, ICalculatorFactory calculatorFactory) 
    { 
     var addCalculator = calculatorFactory.Create("+"); 
     var service = calculatorServiceFactory.Create(addCalculator); 

     // TODO: use the service 
    } 
} 

有優點和缺點使用這種模式,我去了在my answer here。一些好處是,您可以保護自己免受未來更改並避免服務定位器模式。缺點包括界面對象的激增和工廠潛在的病毒使用(見我上面的第一個解決方案,我們必須創建另一個工廠)。

*還有其他的當然,這就是我解決這個特定情況的方式,因爲對我來說,它表示意圖,並且是您的代碼讀者最容易發現的。


根據您的修改關於WCF,我知道你想要做什麼,我會實現,像這樣的服務合同:

public class CalculatorService : ICalculatorService 
{ 
    private readonly ICalculatorFactory calculatorFactory; 
    private ICalculator calculator; 

    public CalculatorService(ICalculatorFactory calculatorFactory) 
    { 
     // store the factory until we need it 
     this.calculatorFactory = calculatorFactory; 
    } 

    public void ChangeCalculatorServiceClient(string operator) 
    { 
     // A new operator, we'll need a new calculator 
     calculator = calculatorFactory.Create(operator); 
    } 
} 

好了,你又」已經改變了你的問題,以包括另一個皺紋;現在你想基於參數實例化一個不同的類型。你可以和應該仍然使用這個工廠,這是我怎麼會去一下吧:

using Castle.Facilities.TypedFactory; 

public class WindsorInstaller : IWindsorInstaller 
{ 
    public void Install(IWindsorContainer container, IConfigurationStore store) 
    { 
     container.Register(
      Component.For<IGreeting, Greeting>(), 
      Component.For<IGreetingFactory>().AsFactory(), 
      Component.For<IGreetingService, GreetingService>(), 
      Component.For<ILanguageFactory, LanguageFactory>()); 
    } 
} 

public interface ILanguageFactory 
{ 
    ILanguage Create(string language); 
} 

public class LanguageFactory : ILanguageFactory 
{ 
    private readonly IKernel kernel; 

    public LanguageFactory(IKernel kernel) 
    { 
     this.kernel = kernel; 
    } 

    public ILanguage Create(string language) 
    { 
     switch (language) 
     { 
      case "S": 
       return kernel.Resolve<Spanish>(); 
      default: 
       throw new ArgumentException(); 
     } 
    } 
} 

public class GreetingService : IGreetingService 
{ 
    private readonly IGreetingFactory greetingFactory; 
    private readonly ILanguageFactory languageFactory; 
    private IGreeting greeting; 

    public GreetingService(IGreetingFactory greetingFactory, ILanguageFactory languageFactory) 
    { 
     // store the factory until we need it 
     this.greetingFactory = greetingFactory; 
    } 

    public string SayHello (string strLanguage) 
    { 
     var language = languageFactory.Create(strLanguage); 
     greeting = greetingFactory.Create(language); 
     return greeting.SayHello(); 
    } 
} 
+0

謝謝,客戶端上的代碼(帶WCF服務引用的Windows窗體)是什麼樣的?就目前而言,我看不到它是如何將運營商傳遞給服務構造函數的。再次感謝。 – w0051977

+0

我不知道哪些代碼是客戶端,所以我不能真正說。 –

+0

你能解釋這是如何回答我的問題嗎?您似乎正在初始化服務中的「操作員」變量。我問的是如何將客戶端的運算符變量,即窗體窗體傳遞給服務構造函數。這可能嗎?對不起,如果我誤解。 – w0051977

相關問題