Injecting data to a WCF service

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.

Leave a Comment

tech