Last time, I posed a conundrum.
Let's say you have a WCF service that implements IMyService. On the client side, you'll have a service reference that derives from ClientBase<IMyService>, which is, in turn, an IDisposable, As I mentioned in the last post, you have two choices:
- You could follow best practices and "program to an interface," namely IMyService. This is not an IDisposable, so you won't be able to properly Dispose() the reference.
- You could abandon your ambition of programming to an interface and use the Client-Base<T>-derived class directly, perhaps with a C# using keyword. This will properly Dispose() the reference.
(We won't mention the worst-of-both-worlds approach in Microsoft's tutorial.)
The first way is bad because it leaves orphaned resources on both the client and the server.
If you use the second method, then you will not be able to use dependency injection. That means your unit tests will depend on a real WCF service. Not only does that mean more setup for your tests, but it means your tests will depend on external software that may or may not be correct. WCF and service-oriented architecture was supposed to avoid exactly this sort of problem.
I'd like to share a solution that has been working quite well for me.
- Create a class, intended for use on the client side, that derives from IMyService. Let's say this class is called MyServiceProxy.
- MyServiceProxy implements each method in IMyService by opening the WCF service at the top of a using block, calling the method, and then let the using block Dispose() the service reference. [Edited to add: Thanks to commenter mathys for pointing out that it's actually a little more complicated than that. If you follow the link he provides, you'll see what you must do at Dispose time if the service is in a faulted state. All the more reason to hide the IDisposable inside MyServiceProxy where you can ensure the Dispose() is handled properly!]
- I use dependency injection to inject an instance of IMyService into whatever code needs it. Let's say the consuming class stores the injected instance in a member variable, _myService.
- The consuming code can then just call _myService.MyMethod().
If the injected instance is the "real" MyServiceProxy class, then MyMethod will open the WCF connection, call MyMethod on the WCF client object, and close the connection.
For unit testing, I can inject a mock of the service. I use the Moq mocking framework, so this is a Mock<IMyService>. The consuming class truly does not care that the mock instance is not an IDisposable. Everything just works.
Although this approach does require me to hand-code a proxy class, I have found that the benefits I get from dependency injection easily repay this modest investment. Not only does dependency injection help me at unit-testing time, but it opens up new possibilities for production code.
For example, let's say we need to improve the performance of our WCF service by caching results on the client side. We can wrap MyServiceProxy using the decorator pattern and get MyCachingServiceProxy. The latter class will also inherit from IMyService. We can inject it into the consuming class, which will get all the benefits of caching with no code changes at all.