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.
- 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.
Read more: Fascinated with Software