Saturday, September 13, 2008

Update on WCF service dependency injection using Spring.NET

I have just uploaded the code that I use for DI in combination with WCF, using Spring.Net.
(better late than never!)

It's up on http://code.google.com/p/agilesquadblog/.
When you svn checkout it is in the AgileSquad.Wcf subfolder.

The instance provider itself is basically a copy/paste out of Oran Dennison's blog.
I have only changed the ReleaseInstance method to dispose of the instance (the service implementation) if it implements IDisposable:

public void ReleaseInstance(InstanceContext instanceContext, object instance)
{
IDisposable disposable = instance as IDisposable;
if(disposable!=null)
{
disposable.Dispose();
}
}

Additional to that the source code includes a working example (visual studio 2008 solution) of the instance provider, test service and configuration.
It includes unit tests to test the spring instance provider.

It also includes some interfaces that I use to abstract the use of WCF channel factory proxies and generated client classes.

The idea behind that is that I don't want my code to reference implementation directly, cause it makes testing more difficult.

So instead of something like:

using (var generatedWcfClient = new GeneratedWcfClient("endPoint"))
{
generatedWcfClient.SendMessage(message);
}

I use something like:

using (IServiceProxy<IMyService> proxy = factory.CreateProxy())
{
proxy.Service.SendMessage(message);
}

In my Service Consumer code. (The factory in the above example is injected through DI of course, see the code)

That means that the code that uses the proxies can be easily configured to use mock or in-memory implementations of the interfaces. It also decouples the use of the specific solution for communicating with a service (WCF in this case). The chance that I will change to some other implementation than WCF is obviously very small. But for testing and decoupling it is great in my opinion. It also decouples the choice of using a generated client or a channel factory.

Check out the code for more details.

The code also includes a ServiceTestEnvironment class that I use to easily test WCF Services. It hosts the WCF Service in a ServiceHost, and allows the unit test to call the service using a proxy and SetUp and TearDown the "environment". In the Test project I use the above mentioned IServiceProxy and IServiceProxyFactory interfaces. The ChannelFactory implementation is used, as a generated proxy would start conflicting (ambiguous references)with the service code because you would have to reference both the client and the server in this way of testing.

2 comments:

  1. Hi,

    I'm facing a similar issue, I was wondering if you could help me, maybe you know the answer.

    I'm referencing a WCF service (hosted in IIS) in my remote application. In order to call the service I use the generated client class:

    MyServiceClient client = new MyServiceClient("BasicHttpBinding_IMetricaService");

    client.MethodA();

    What I don't understand is, when I call MethodA() above, my service should be initialised and injected what it requires (a DAO object).

    In other words, where should I put the code that you wrote in TestInstanceProvider(), the bit that gets the Spring context.

    I hope this is clear enough :)
    Thanks

    ReplyDelete
  2. Hi Samuel,

    You need to setup your config correctly, so that the injection happens automatically when the service is created by the framework.

    If you look in the example that I put on code.google.com, check out the appconfig.xml file. This is on the server side of the example.

    The part that I put in the TestInstanceProvider method is to get a reference to the factory of service proxies (something I use to abstract the proxy interface), which is on the client side. It has nothing to do with the injection of the wcf service.

    Hope that helps!

    ReplyDelete