IDisposable, WCF, and Hole In The Middle
Steve Smith recently posted about the problem of the Close() (or Dispose()) method throwing an exception in WCF. He proposed a solution that was an extension method to the ICommunicationObject interface and handled safely closing the connection. Now, if you read my blog you likely know I love Extension Methods, and even more so love them on Interfaces, but his code resulted in a usage like this:
var myClient = new ServiceClient();
int someValue = myClient.GetSomeValue();
myClient.CloseConnection(); // extension method
This is ok, but as he noted doesn’t actually save you much over a using() block except that the error is not thrown from a closing brace, which is confusing. But if you look at this code, it is a classic example of a Hole In The Middle. We want to do some common setup, and common tear down, but do something different in the middle. The easiest way to get around Hole In The Middle problems in C# is to use lambdas. But of course we want to do this in a way that is easy, and preserves our type safety.
So I sat down with Visual Studio, and after about 15 minutes came up with this:
public static TResult SafeExecution<TExtension, TResult>
(this TExtension myServiceClient,
Func<TExtension, TResult> serviceAction)
where TExtension : ICommunicationObject
outValue = serviceAction.Invoke(myServiceClient);
This solution uses the CloseConnection extension method Steve created, but results in a usage that looks like this:
var ec2 = new Amazon.AmazonEC2PortTypeClient();
ec2.SafeExecution(i => i.AllocateAddress(null));
As you can see, this is a more compact, but still type-safe way of addressing this problem and does so with an Extension Method so you can re-use this code in any project you encounter.
This is a new solution to me, so I’m certainly open to comments, but I think it is an elegant solution. What do you think?