Dot-Net

將數據注入 WCF 服務

  • January 11, 2010

我有Miguel Castro建議的 WCF 服務結構。這意味著我已經手動設置了所有內容,並且有一個控制台應用程序使用ServiceHost對象託管我的服務。

我想讓我的服務類保持精簡,它們目前只是將呼叫傳遞給行為類。我現在的問題是對服務類進行單元測試。我想將一些東西作為建構子參數注入到類中,這樣我就可以模擬它並編寫適當的隔離單元測試。ServiceHost 類似乎不接受參數,所以我的問題是如何將數據注入服務類 - 還是不能?

WCF 支持Constructor Injection,但您必須跳過幾個圈才能到達那裡。關鍵在於編寫一個自定義的 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 容器或使用 Poor Man 的 DI 來實現依賴注入。

這是使用Poor Man’s DI的這個成語的舊文章。

引用自:https://stackoverflow.com/questions/2042609