Sunday, March 8, 2009

WCF Proxies and Abstract Factories

Okay, so you've built your WCF service for your distributed application.

[ServiceContract]
public interface IMyService
{
[OperationContract]
void DoSomething(bool Fail);
}

And you're consuming it from your client application, and because you're a smart guy you know that your proxy implements IDisposable and you can call it with a 'using' statement.

using (MyServiceClient proxy = new MyServiceClient())
{
proxy.DoSomething(true);
}

So now you know that even if your call fails for some reason your proxy will still clean up and go home. But then your service throws a FaultException one day and passes it to your client application, and your client application wants to tell you about this exception really really bad but all it can say is "The communication object, System.ServiceModel.Channels.ServiceChannel, cannot be used for communication because it is in the Faulted state." What gives?

And then it hits you: this exception is happening when you try to dispose of your proxy and it's covering up the exception that should be getting thrown outside of the using statement.

See, there are two ways to close your client proxy: you can call Close() on the proxy, which only works when the proxy is not in a Faulted state. You can also call Abort() on the proxy, which closes it regardless of what state it's in. Guess which one the proxy's Dispose() method calls?

So now your proxy call looks like this:

using (MyServiceClient proxy = new MyServiceClient())
{
try
{
proxy.DoSomething(true);
}
catch (Exception)
{
proxy.Abort();
throw;
}
}


(This is an over-simplification. Of course you're going to do something with that exception like email it to the support team and buy the user a drink.)

And now you have to do that for every service call you make from your client application. Three lines are now twelve lines. In the grand scheme of things, it's a minor annoyance. But it got me thinking. I use an abstract factory to return my proxy instance because I have a different endpoint for my production and development regions.

internal static class ProxyFactory
{
internal static MyServiceClient GetProxy()
{
return new MyServiceClient();
}
}

I'd love to be able to write this new boilerplate code into my abstract factory method instead of including it in every call I make. And with anonymous methods I can do it. It only requires a little more complexity than my abstract factory method.

First I create a delegate with one input parameter for the interface our proxy supports.

internal delegate void MyServiceProxyHandler(IMyService proxy);


Then I change my factory method to do this:

internal static void MakeProxyCall(MyServiceProxyHandler OurMethod)
{
using (MyServiceClient proxy = new MyServiceClient())
{
try
{
OurMethod(proxy);
}

catch (Exception)
{
proxy.Abort(); throw;
}
}
}

Now every call I make looks like this:

ProxyFactory.MakeProxyCall(delegate(IMyService proxy)
{
proxy.DoSomething(true);
});

Or this (if you're a lambda cowboy):

ProxyFactory.MakeProxyCall(p => p.DoSomething(true)); -- one line. woop woop!

If my call fails for some reason, I don't need to worry about closing the proxy because it's already done for me. And any exceptions still get thrown outside the using statement and passed on to the calling code. I can even centralize my notification logic inside the factory method. Say I wanted to send an email every time a CommunicationException was encountered. I could create a separate catch block for CommunicationExceptions, add my notification code, and throw the error back out to the calling code.

An additional benefit comes from the fact that each WCF call is now completely focused on the interface which allows me to abstract away all the plumbing and even stub in a local mock class that implements the same interface for testing purposes. Plus if I wanted to change the way I was making every single WCF call, I'd have to search through all of my code for each service call and change the structure of each call. With the new ProxyFactory method, I change the code in one place.

There are two things that I lose in doing all my calls this way:

1) I'm instantiating my proxy every time I make a call, so any benefit I might gain from having a stored proxy is lost. This, of course, could be worked around in the ProxyFactory class by keeping a static instance of the proxy around, not encapsulating the call in a using statement, and only aborting the proxy when the call fails and re-creating it (I'll leave this as an exercise for the reader).

2) I can't make asynchronous calls with the proxy, again because I'm closing the proxy in the factory method so I don't have anything to call the End* method on. This doesn't concern me that much because any long running calls can be handled in my code by a BackgroundWorker process. And if it really got to be a pain, I'm sure I could figure out a way to overcome it in my ProxyFactory (I'll leave this as an exercise for an even more eager reader).

No comments:

Post a Comment