DCSIMG

I'm on a mission from God object

Yaniv Rodenski

News



Oredev Hadoop Azure

QCon new-york Hadoop Azure

NDC Hadoop Azure

View Yaniv Rodenski's LinkedIn profileView Yaniv Rodenski's profile

January 2012 - Posts

Improve WCF services testability with simple Dependency Injection

Dependency injection is a great technique to reduce coupling between components and improve testability. There are few techniques we can create dependency injections, you can use a framework like MEF or spring to Automate dependency injection but I personally favor manually injected dependencies. call me old fashion, but I like creating object via simple constructor calls (most of the time).

This is really straight forward most of the time but when dealing with WCF services there is a slight complexity to take in to consideration. In most scenarios WCF is in charge of instantiating the service class (the only exception here is with single instance context mode, where we can supply ServiceHost with a ready made instance of our service class).

Lately I have come across a really cool (and simple) option in WCF Web API. The WCF Web API supply an HttpConfiguration API that exposes a CreateInstance delegate we can use to manually create a new instance of our service class:

HttpConfiguration config = new HttpConfiguration();
config.CreateInstance = (type, context, message) =>
{
    IPlayersDal dal = new PlayersDal();
    return new PlayersCURD(dal);
};

var factory = new HttpServiceHostFactory() { Configuration = config };

While this API is cool, it can only be used for http based services (using the WCF Web API). I really felt like using something like that in a SOAP based project I am currently working on so I figured what the hack, I can create the similar solution (source code can be found here) for any WCF service host out there.

The first stop was creating an IExtension<ServiceHostBase> that can transport the delegate down the WCF pipeline:

class InstanceInitializerExtension : IExtension<ServiceHostBase>
{
    public Func<object> InstanceInitializer;

    public void Attach(ServiceHostBase owner)
    {
    }

    public void Detach(ServiceHostBase owner)
    {
    }
}

Next we need to create an instance provider. this is the runtime component that WCF actually uses to create a new instance of the service class:

public class ManualInstanceProvider : IInstanceProvider
{
    public object GetInstance(InstanceContext instanceContext, Message message)
    {
        var extension = instanceContext.Host.Extensions.Find<InstanceInitializerExtension>();
        return extension.InstanceInitializer();
    }

    public object GetInstance(System.ServiceModel.InstanceContext instanceContext)
    {
        return GetInstance(instanceContext, null);
    }

    public void ReleaseInstance(System.ServiceModel.InstanceContext instanceContext, object instance)
    {
    }
}

To hook the the ManualInstanceProvider we need to create a service behavior and implement the ApplyDispatchBehavior method like this:

public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
    foreach (ChannelDispatcherBase cdb in serviceHostBase.ChannelDispatchers)
    {
        ChannelDispatcher cd = cdb as ChannelDispatcher;
        if (cd != null)
        {
            foreach (EndpointDispatcher ed in cd.Endpoints)
            {
                ed.DispatchRuntime.InstanceProvider = new ManualInstanceProvider();
            }
        }
    }
}

The last thing we need to do is create an extension method for ServiceHostBase that will allow setting the delegate as the factory function of our host:

public static void ConfigureInstanceFactory(this ServiceHostBase host, Func<object> instanceInitializer)
{
    // adding a behavior that hocks up the ManualInstanceProvider
    host.Description.Behaviors.Add(new InstanceCreationBehavior());

    // passing the instance initialize down the rabbit hole
    host.Extensions.Add(new InstanceInitializerExtension
                            { InstanceInitializer = instanceInitializer });
}

Now we are ready to create our service host:

var host = new ServiceHost(typeof(PlayersService));
host.ConfigureInstanceFactory(() => new PlayersService(new PlayersDal()));

host.Open();

Summary

Using dependency injection can some (if not most) of the time a simple task. Using this extension we can utilize whichever technique we choose.

Yaniv

kick it on DotNetKicks.com Shout it

MSDN Israel Windows Azure and SQL Azure forum

I am very happy to announce the opening of a new Windows Azure and SQL Azure forum in Hebrew. The new forum is managed by Shay Friedman and myself. Azure

If you are new to Windows Azure, I would like to use this opportunity to invite you to experience cloud development with our support and guidance. If you are already experienced with Windows Azure development I would like to assure you that you can find in our forum help from highly experienced professionals.

With your participation I am sure we can create an awesome and vibrant community.

Hope the catch you there soon

Yaniv