Improve WCF services testability with simple Dependency Injection

30 בינואר 2012

2 comments

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

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

2 comments

  1. Yuji21 ביולי 2012 ב 23:30

    Yeah, I think perhaps that the alertnative term Inversion of Control (which IIRC Fowler doesn't like) illustrates a little better the difference between DI and Service Locator. With DI frameworks (that I've used in Java, anyway), the important difference is that the classes do not have any links/knowledge of any external registry (i.e. service locator). Everything is just a very simple object and the dependencies are set (injected) in by an external agent. This gives you lots & lots of control over both what is instantaited (i.e. which particular classes and what params they are passed) and how those classes are instantiated (e.g. singleton or new instance for every object). Another feature of a centralized DI/IoC framework is that you have a single place where AOP cutpoints, advice, etc. can be defined for your objects. A DI solution almost has a language-level feel about it (indeed, it feels like a bit of hack to me with frameworks like Spring, since one is essentially writing application code in XML).I still don't see how a true DI solution would work in PHP, though (as I mention on Jeff's blog). To really wire everything up would add an unnacceptable level of overhead to my PHP scripts e.g. my framework may require that certain objects get wired with a desired ImageTransformer driver, but 90% of my page requests don't need an ImageTransformer at all.This appears to me to be a problem that is inherent in trying to invert control for an environment like PHP. Because PHP environments must (generally) be recreated for every request, there is a good reason to keep control of the object setup on-demand within the service classes themselves i.e. with PHP there is a good reason not to invert control. Now, I suppose that this wouldn't be the case if the IoC layer could somehow magically wire-on-demand. But any implementation I can think for that just starts to look like a service locator.-H

    Reply
  2. Mares14 בנובמבר 2012 ב 20:30

    Hi, I do think this is an excellent site. I stumbledupon it ;
    ) I'm going to return once again since I book-marked it. Money and freedom is the greatest way to change, may you be rich and continue to guide other people.

    Diet Programs That Work

    Reply