Dot-Net
將數據注入 WCF 服務
我有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的這個成語的舊文章。