将数据注入到WCF服务
我有像Miguel Castrobuild议的WCF服务。 这意味着我已经手动设置了一切,并有一个控制台应用程序托pipe我的服务使用ServiceHost对象。
我想保持我的服务类的精简,他们目前只是将调用传递给行为类。 我现在的问题是unit testing服务类。 我想注入一些东西作为一个构造参数的类,我可以嘲笑这一点,并写出适当的隔离unit testing。 ServiceHost类似乎不接受参数,所以我的问题是如何可以将数据注入服务类 – 或者我不能?
WCF支持构造函数注入 ,但你必须跳过几个箍来到那里。 关键在于编写一个自定义的ServiceHostFactory。 虽然这也必须有一个默认的构造函数,你可以用它来连接所有正确的行为。
举个例子,我最近写了一个使用Castle Windsor来连接服务实现的依赖关系。 CreateServiceHost的实现只是这样做的:
return new WindsorServiceHost(this.container, serviceType, baseAddresses);
其中this.container
是一个configuration的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来实现dependency injection。
这是一个较老的写这个成语,使用穷人的DI。
如果你使用的是温莎城堡,那么它有一个伟大的WCF集成工具,可以让你做到这一点,而且更容易。
你configuration你的服务作为一个单身? 我发现使用DI容器创build服务实例时,IInstanceProvider实现可能会有问题。
文章将一个Mock作为一个WCF服务包含一个静态方法,该方法将根据传递给具有单个端点的方法的对象生成一个WCF服务主机。
该方法也发布在unit testingWeb服务的推荐模式的答案中。
使用示例调用NSubstitute,但也可以使用其他嘲笑freameworks。