首页 文章

将数据注入WCF服务

提问于
浏览
20

我有像Miguel Castro建议的WCF服务结构 . 这意味着我已手动设置所有内容,并使用ServiceHost对象托管我的服务的控制台应用程序 .

我想保持我的服务类很薄,他们目前只是调用行为类 . 我现在的问题是单元测试服务类 . 我想向类中注入一些东西作为构造函数参数,这样我就可以模拟它并编写适当的隔离单元测试 . ServiceHost类似乎不接受参数,所以我的问题是如何将数据注入服务类 - 或者我不能?

4 回答

  • 0

    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容器或使用穷人的DI实现依赖注入 .

    这是使用穷人的DI的这个成语的older writeup .

  • 31

    如果你使用Castle Windsor,它有一个很棒的WCF集成工具,可以让你做到这一点,而且非常容易 .

  • 5

    你是否将服务配置为Singleton?我发现使用DI容器创建服务实例时,IInstanceProvider实现可能会有问题 .

  • 1

    文章Hosting a Mock as a WCF service包含一个静态方法,该方法将根据使用单个 endpoints 传递给方法的对象生成WCF服务主机 .

    该方法也发布在answerRecommended patterns for unit testing web services .

    使用示例调用NSubstitute,但可以使用其他模拟freameworks .

相关问题