Isolating WCF through Dependency Injection – Part II
02/07/2009
In my previous post, I talked about how to design a class that uses a WCF client proxy in such a way to make it testable in unit tests, without having to spin up a real service to answer the requests.
The technique I illustrated uses a particular Inversion of Control (IoC) principle called Dependency Injection (DI), in which objects that a given class depends on get pushed into it from the outside rather than being created internally.
In this particular case, the external dependency is represented by a WCF client proxy targeting a particular service. This approach enables me to swap the real proxy objects used in production with test doubles while running unit tests, making it possible to assert the class’s behavior in a completely isolated and controlled environment.
Moving from concrete classes to interfaces
Last time we left off with a MailClient class that takes an instance of ChannelFactory<MailServiceClientChannel> in the constructor and uses it internally every time it needs to download Email messages by following three steps:
- Creating a new proxy instance configured to communicate with the remote MailService service
- Invoking the GetMessages operation on the service
- Disposing the proxy
However, as I pointed out before, being the ChannelFactory<TChannel> a concrete class, creating a test double for it isn’t very convenient. A much better approach would be having the MailClient class interact with an interface instead. This way it would be easy to create a fake factory object in unit tests and have the class use that instead of the real one.
After a quick look in the online MSDN Documentation I found that the ChannelFactory<TChannel> class indeed implements the IChannelFactory<TChannel> interface. “Sweet, I can use that!” I thought. But there’s a catch:
The IChannelFactory<TChannel>.CreateChannel factory method requires the caller to pass along an EndpointAddress object, which contains information about where and how to reach the service, like the URI and the Binding.
This isn’t really what I wanted, since it forced the MailClient class to have knowledge of where the remote service is located or at the very least how to obtain that piece of information. This doesn’t really conform to the Dependency Injection principle, since these details naturally belong to the dependent object, and should therefore be handled outside the scope of the class.
The ChannelFactory adapter
The solution I came up with is to create an adapter interface to hide these details from my class. The implementation of this interface would then wrap a properly configured instance of ChannelFactory<TChannel> and delegate all the calls it receives to it.
Here is the definition of the adapter interface:
using System.ServiceModel;
public interface IClientChannelFactory<TChannel>
where TChannel : IClientChannel
{
void Open();
void Close();
void Abort();
TChannel CreateChannel();
}
And here is the default implementation:
using System;
using System.ServiceModel;
public class ClientChannelFactory<TChannel> : IClientChannelFactory<TChannel>
where TChannel : IClientChannel
{
private ChannelFactory<TChannel> factory;
public ClientChannelFactory(string endpointConfigurationName)
{
this.factory = new ChannelFactory<TChannel>(endpointConfigurationName);
}
public void Open()
{
this.factory.Open();
}
public void Close()
{
this.factory.Close();
}
public void Abort()
{
this.factory.Abort();
}
public TChannel CreateChannel()
{
return this.factory.CreateChannel();
}
}
As you can see by using generics we are able to create an implementation that works for different types of proxies.
Notice also that the class requires the callers to specify the name of the configuration element used to describe the service endpoint in the constructor. This way the MailClient class is completely isolated from having to know about WCF configuration details, and can instead concentrate on its core responsibility, that is to invoke operations on the service and work with the results.
Here is the final MailClient implementation:
public class MailClient
{
private IClientChannelFactory<IMailServiceClientChannel> proxyFactory;
public MailClient(IClientChannelFactory<IMailServiceClientChannel> proxyFactory)
{
this.proxyFactory = proxyFactory;
}
public EmailMessage[] DownloadMessages(string smtpAddress)
{
// Validate the specified Email address
IMailServiceClientChannel proxy;
try
{
proxy = proxyFactory.CreateChannel();
Mailbox request = new Mailbox(smtpAddress);
EmailMessage[] response = proxy.GetMessages(request)
// Do some processing on the results
proxy.Close();
return response;
}
catch(Exception e)
{
proxy.Abort();
throw new MailClientException("Failed to download Email messages", e);
}
}
}
The only modification is in the type of the argument declared in the constructor, which is now an interface.
Finally unit testing
We are now able to test our class in isolation by creating fake objects that implement the IClientChannelFactory and IMailServiceClientChannel interfaces respectively, and inject them into our object under test.
In this particular example I am using Rhino Mocks as an isolation framework to create and manage test doubles, but I could as well used just about any other isolation framework out there, such as Typemock Isolator, with the same result.
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Rhino.Mocks;
[TestClass]
public class MailClientTest
{
[TestMethod]
public void DownloadMessages_WithValidEmailAddress_ReturnsOneMessage()
{
// Fakes out the WCF proxy
var stubProxy = MockRepository.CreateStub<IMailServiceClientChannel>();
// Stubs the service operation invoked by the class under test
stubProxy
.Stub(m => m.GetMessages(Arg<string>.Is.Anything))
.Returns(new EmailMessage[0]);
// Fakes out the WCF proxy factory
var stubProxyFactory = MockRepository.CreateStub<IClientChannelFactory<IMailServiceClientChannel>>();
// Stubs the factory method to return the mocked proxy
stubProxyFactory
.Stub(s => s.CreateChannel())
.Return(stubProxy);
var testObject = new MailClient(stubProxyFactory);
EmailMessage[] results = testObject.DownloadMessages("test@test.com");
Assert.AreEqual(0, results.Length, "The method was not supposed to return any results");
}
}
This concludes this short series of posts on how to apply Dependency Injection to classes that consume WCF services in order to easily test them in isolation with unit tests. I hope this helps.
/Enrico




24/07/2009 at 09:39
Hi Enrico,
would you perhaps have a small downloadable sample solution? What is specifically unclear to me is (mainly from Part I) is how you configure the endpoint.
What I am looking to do is have a client (Winform in this case) to consume a WCF service but to couple the two via Unity using a config file as much as possible. I think your articles are the closest thing I have yet found that illustrate how to do this but I’m just missing a few bits and pieces that have prevented me from getting it to work.
Maybe even just posting your app.config would suffice.
Thanks!
25/07/2009 at 13:52
Hi,
Thanks for pointing that out. I added a sample WCF configuration in the Part I post. You’ll find it towards the end of the page. Please, let me know if you would like any further clarification.
/Enrico
01/03/2010 at 20:44
Enrico, can you show what you changed to set up Unity once you implemented IClientChannelFactory?
05/03/2010 at 10:55
Hi Jason,
I registered the IClientChannelFactory<TChannel> interface to map to the concrete ClientChannelFactory<TChannel> class in my Unity container. Here is an example:
var container = new UnityContainer(); container .RegisterType<IClientChannelFactory<IMailServiceClientChannel>>() .Configure<InjectedMembers>() .ConfigureInjectionFor<ClientChannelFactory<IMailServiceClientChannel>>( new InjectionConstructor("localMailServiceEndpoint"));A new instance of the ClientChannelFactory<IMailServiceClientChannel> class will now automatically be passed to every new MailClient object created through Unity.
Hope this helps.
/Enrico
13/04/2010 at 04:30
This is awesome! One question though. Our message exchange pattern is request/response and wrapped. One thing I noticed (we use Moq, not RhinoMocks or others) though is that Moq requires .Equals() implementation on the messages. Assuming other mocking libraries implement similarly, how would you deal with having to be intrusive with the svcutil-generated client?
Tim
20/04/2010 at 09:36
Hi Tim,
If I understand your scenario correctly, you want to create stubs or mocks for the message objects being passed between the service and the client. In particular you need to fake the Equals method and the problem is that those classes are auto-generated so you can’t really modify them.
In this case I would use a technique called Extract & Override, which I picked up by the excellent book The Art of Unit Testing by Roy Osherove. Using this technique you could fake an auto-generated message class by creating a new derived class and override the Equals method (which is inherited from Object) to replace its implementation with your own.
Here is an example:
// Auto-generated message class // created by the svcutil tool public class RequestMessage { } // Fake message class public class FakeRequestMessage : RequestMessage { public override Equals() { // Fake implementation } }I hope this helps.
/Enrico
25/02/2011 at 10:14
What is IMailServiceClientChannel ? thanks
03/03/2011 at 11:16
@David
IMailServiceChannelis an interface that inherits both from theIMailServiceservice contract and the System.ServiceModel.IClientChannel interface. This way it becomes possible to properly release the communication channel created with the System.ServiceModel.ChannelFactory by invoking the IClientChannel.Close and IClientChannel.Abort methods.16/04/2012 at 13:08
This is probably one of the best samples I have found on this. However, it would be really handy to have a complete source code download, because as always with blog posts the extracts always leave out an essential bit of info.
Please could you provide a source code download?
14/11/2012 at 08:15
Hi,
you go to all this effort to post a blog and then no sample provided makes all useless as sometimes you might miss something.
Why dont you provide an example download and then you it would be perfect no?
27/02/2013 at 16:38
Silly question: what is the point of Open(), Close(), and Abort() in IClientChannelFactory? I see in the default implementation, these methods are just calling the internal channel factory versions. However, what would be calling these methods via IClientChannelFactory?
01/03/2013 at 11:14
@Ralph That’s a very good observation. The reason why I chose to expose those methods in the
IChannelFactoryAdapterinterface is to allow the client to manage the lifetime of the internalChannelFactoryinstance in a deterministic fashion. For example, one might want to reuse the sameChannelFactoryAdapterinstance across different components and explicitly close it at a specific point in time, thus releasing all channels that were created by it at once.On the other hand, I recognize that having the
Open,CloseandAbortmethods on both theChannelFactoryand theIClientChannelinstances it creates is somewhat ambiguous. However, since we’re building an abstraction on top of theChannelFactory(albeit a very thin one) one could take the chance to simplify its API by removing those methods from the adapter interface. This would give clients one consistent way to manage the lifetime of the channels they create.I hope this helps in answering your question.