Making the HttpMessageHandlerFactory in WCF Web Apis more DI friendly

The HttpMessageHandlerFactory shipped out of the box in the WCF Web Apis Preview 4 can only construct channels instances with a single argument in the constructor representing the inner channel in the pipeline.

public abstract class DelegatingChannel : HttpMessageChannel
{
    protected DelegatingChannel(HttpMessageChannel innerChannel);

This is the constructor that the factory always try to invoke by default. However, this approach does not work well when you need to inject some dependencies into the channels for doing some real work and making the channel more testable.

Going back to the example I shown a couple of weeks ago for doing a key validation, the key validator was an external dependency I had to inject into my channel.

public class ApiKeyVerificationChannel : DelegatingChannel
{
    public const string KeyHeaderName = "X-AuthKey";
 
    IKeyVerifier keyVerifier;
 
    public ApiKeyVerificationChannel(HttpMessageChannel innerChannel)
        : this(innerChannel, new KeyVerifier())
    {
    }
 
    public ApiKeyVerificationChannel(HttpMessageChannel innerChannel, IKeyVerifier keyVerifier)
        : base(innerChannel)
    {
        this.keyVerifier = keyVerifier;
    }

At that time, I just used a poor man DI solution for passing that dependency to the channel. The constructor invoked by the factory was creating an instance of the concrete implementation and passing that to the constructor receiving the dependency as an interface.

The good thing is that the HttpMessageHandlerFactory can be extended to support other strategies, so that’s what I am going to do as part of this post to show how the factory can be extended to inject any number of external dependencies into the channels.

public class CustomHttpMessageHandlerFactory : HttpMessageHandlerFactory
{
    Func<HttpMessageChannel, DelegatingChannel>[] factories;
 
    public CustomHttpMessageHandlerFactory()
        : base()
    {
    }
 
    public CustomHttpMessageHandlerFactory(params Func<HttpMessageChannel, DelegatingChannel>[] factories)
    {
        this.factories = factories;
    }
 
    protected override HttpMessageChannel OnCreate(HttpMessageChannel innerChannel)
    {
        if (innerChannel == null)
        {
            throw new ArgumentNullException("innerChannel");
        }
 
        HttpMessageChannel pipeline = innerChannel;
 
        foreach (var factory in this.factories)
        {
            pipeline = factory(innerChannel);
        }
 
        return pipeline;
    }
}

The trick here is to pass an array of Func delegates representing factories for the channels as part of the constructor, and override the OnCreate method to actually instantiate those channels with the delegates.

This makes possible to do things like the following to instantiate the channels as part of the configuration,

var keyVerifier = new KeyVerifier();
 
var config = HttpHostConfiguration.Create()
    .SetMessageHandlerFactory(new CustomHttpMessageHandlerFactory(innerChannel =>
        new ApiKeyVerificationChannel(innerChannel, keyVerifier)));
 
// setting up contacts services
RouteTable.Routes.MapServiceRoute<ContactsResource>("contacts", config);

As you can see, I am passing a lambda expression for instantiating the ApiKeyVerificationChannel with an existing IKeyVerifier instance. No need to use the Poor Man DI approach anymore Smile. You can also extend this example and resolve things like the IKeyVerifier from a service container, but I will let that part as homework for the reader.

Comments

No Comments