2010-01-11 54 views
18

我有像Miguel Castro建議的WCF服務。這意味着我已經手動設置了所有內容,並使用ServiceHost對象來託管我的服務。將數據注入WCF服務

我想保持我的服務類更加簡潔,他們目前只是將調用傳遞給行爲類。我現在的問題是單元測試服務類。我想向類中注入一些東西作爲構造函數參數,這樣我就可以將它嘲諷並編寫適當的單元測試。 ServiceHost類似乎不接受參數,所以我的問題是如何將數據注入服務類 - 或者我不能?

+0

您使用的是IoC容器嗎?如果是的話,哪一個? – Fabiano 2010-01-11 16:35:47

+0

我還沒有在服務器端使用IoC容器。計劃現在介紹一個。我在客戶端使用Unity(與Prism一起使用),但請考慮在服務器上使用StructureMap。爲任何人開放。 – stiank81 2010-01-11 17:59:47

回答

29

WCF支持構造函數注入,但你必須通過幾個箍來到那裏。關鍵在於編寫一個自定義的ServiceHostFactory。雖然這也必須有一個默認的構造函數,你可以用它來連接所有正確的行爲。例如,我最近編寫了一個使用Castle Windsor來連接服務實現的依賴關係的例子。 CreateServiceHost的實現只是做到這一點:

return new WindsorServiceHost(this.container, serviceType, baseAddresses); 

其中this.container是配置IWindsorContainer。

WindsorServiceHost看起來是這樣的:

public class WindsorServiceHost : ServiceHost 
{ 
    public WindsorServiceHost(IWindsorContainer container, Type serviceType, params Uri[] baseAddresses) 
     : base(serviceType, baseAddresses) 
    { 
     if (container == null) 
     { 
      throw new ArgumentNullException("container"); 
     } 

     foreach (var cd in this.ImplementedContracts.Values) 
     { 
      cd.Behaviors.Add(new WindsorInstanceProvider(container)); 
     } 
    } 
} 

和WindsorInstanceProvider看起來是這樣的:

public class WindsorInstanceProvider : IInstanceProvider, IContractBehavior 
{ 
    private readonly IWindsorContainer container; 

    public WindsorInstanceProvider(IWindsorContainer container) 
    { 
     if (container == null) 
     { 
      throw new ArgumentNullException("container"); 
     } 

     this.container = container; 
    } 

    #region IInstanceProvider Members 

    public object GetInstance(InstanceContext instanceContext, Message message) 
    { 
     return this.GetInstance(instanceContext); 
    } 

    public object GetInstance(InstanceContext instanceContext) 
    { 
     var serviceType = instanceContext.Host.Description.ServiceType; 
     return this.container.Resolve(serviceType); 
    } 

    public void ReleaseInstance(InstanceContext instanceContext, object instance) 
    { 
     this.container.Release(instance); 
    } 

    #endregion 

    #region IContractBehavior Members 

    public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) 
    { 
    } 

    public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime) 
    { 
    } 

    public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime) 
    { 
     dispatchRuntime.InstanceProvider = this; 
    } 

    public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint) 
    { 
    } 

    #endregion 
} 

這看起來好像很多,但是請注意,它是有一個相當可重複使用的,通用的代碼低圈複雜度。

您可以按照相同的編碼慣例,通過另一個DI Container或使用Poor Man的DI來實現依賴注入。

這是一個older writeup這個使用窮人的DI的成語。

+0

Thx爲您的答覆。看起來很有希望!明天就會發現它! – stiank81 2010-01-11 22:42:41

+0

非常有幫助的答案。 – 2010-09-08 04:17:03

+0

這種方法的優點是什麼,而不是使用Wcf設施? – CrazyDart 2011-03-18 22:45:35

1

您是否將您的服務配置爲Singleton?我發現使用DI容器創建服務實例時,IInstanceProvider實現可能會出現問題。

5

如果您使用的是Castle Windsor,它擁有一個很棒的WCF集成工具,可以讓您輕鬆做到這一點。

0

文章Hosting a Mock as a WCF service 包含一個靜態方法,該方法將根據傳遞給具有單個端點的方法的對象生成WCF服務主機。

該方法也發佈在的answer中。

使用示例調用NSubstitute,但可以使用其他嘲笑freameworks。