将数据注入 WCF 服务

Posted

技术标签:

【中文标题】将数据注入 WCF 服务【英文标题】:Injecting data to a WCF service 【发布时间】:2011-01-03 19:08:34 【问题描述】:

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

我想让我的服务类保持精简,它们目前只是将调用传递给行为类。我现在的问题是对服务类进行单元测试。我想将一些东西作为构造函数参数注入到类中,这样我就可以模拟它并编写适当的隔离单元测试。 ServiceHost 类似乎不接受参数,所以我的问题是如何将数据注入服务类 - 还是不能?

【问题讨论】:

您使用的是 IoC 容器吗?如果是,是哪一个? 我还没有在服务器端使用 IoC 容器。现在打算介绍一个。我在客户端使用 Unity(与 Prism 一起提供),但考虑在服务器上使用 StructureMap。真的对任何人开放。 【参考方案1】:

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 容器或使用可怜人的 DI 来实现依赖注入。

这是使用Poor Man's DI的这个成语的older writeup。

【讨论】:

当我最初写这个答案时,温莎 WCF 设施并没有处于任何稳定状态。无论如何,答案解​​释了如何使用任何 DI 容器支持 WCF 中的构造函数注入:只需将 IWindsorContainer 替换为您选择的容器。【参考方案2】:

如果您使用的是 Castle Windsor,它具有出色的 WCF 集成工具,可让您轻松完成此操作。

【讨论】:

【参考方案3】:

您是否将您的服务配置为单例?我发现在使用 DI 容器创建服务实例时,IInstanceProvider 实现可能会出现问题。

【讨论】:

【参考方案4】:

文章Hosting a Mock as a WCF service 包含一个静态方法,该方法将基于通过单个端点传递给该方法的对象生成 WCF 服务主机。

该方法也发布在answer for Recommended patterns for unit testing web services。

使用示例调用 NSubstitute,但可以使用其他模拟框架。

【讨论】:

以上是关于将数据注入 WCF 服务的主要内容,如果未能解决你的问题,请参考以下文章

WCF 自定义行为的依赖注入

autofac 注入普通服务和WCF服务

使用 Castle Windsor 进行 WCF 依赖注入 - 请帮忙?

预处理器指令反射注入

进行依赖注入时未找到 WCF 引用

如何注入服务一些数据? [关闭]