Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
100 views
in Technique[技术] by (71.8m points)

.net - Injecting data to a WCF service

I have WCF services structured like suggested by Miguel Castro. This means that I have set everything up manually, and have a console application hosting my services using ServiceHost objects.

I want to keep my service classes thin, and they are currently just passing on calls to behavior classes. My problem now is unit testing the service classes. I want to inject something to the classes as a constructor parameter such that I can mock this away and write proper isolated unit tests. The ServiceHost class doesn't seem to accept arguments, so my question is how I can inject data to the service classes - or can't I?

Question&Answers:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

WCF supports Constructor Injection, but you have to jump through a few hoops to get there. The key lies in writing a custom ServiceHostFactory. While that, too, must have a default constructor, you can use it to wire up all the correct behaviors.

As an example, I recently wrote one that uses Castle Windsor to wire up dependencies for the service implementation. The implementation of CreateServiceHost simply does this:

return new WindsorServiceHost(this.container, serviceType, baseAddresses);

where this.container is a configured IWindsorContainer.

WindsorServiceHost looks like this:

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));
        }
    }
}

and WindsorInstanceProvider looks like this:

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
}

This may look like a lot, but notice that it's reusable, general-purpose code that has a rather low cyclomatic complexity.

You can follow the same coding idiom to implement Dependency Injection with another DI Container or by using Poor Man's DI.

Here's an older writeup of this idiom that uses Poor Man's DI.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...