I wrote a higher order function to make it work right. We've used this in several projects and it seems to work great. This is how things should have been done from the start, without the "using" paradigm or so on.
TReturn UseService<TChannel, TReturn>(Func<TChannel, TReturn> code)
{
var chanFactory = GetCachedFactory<TChannel>();
TChannel channel = chanFactory.CreateChannel();
bool error = true;
try {
TReturn result = code(channel);
((IClientChannel)channel).Close();
error = false;
return result;
}
finally {
if (error) {
((IClientChannel)channel).Abort();
}
}
}
You can make calls like this:
int a = 1;
int b = 2;
int sum = UseService((ICalculator calc) => calc.Add(a, b));
Console.WriteLine(sum);
This is pretty much just like you have in your example. In some projects, we write strongly typed helper methods, so we end up writing things like "Wcf.UseFooService(f=>f...)".
I find it quite elegant, all things considered. Is there a particular problem you encountered?
This allows other nifty features to be plugged in. For instance, on one site, the site authenticates to the service on behalf of the logged in user. (The site has no credentials by itself.) By writing our own "UseService" method helper, we can configure the channel factory the way we want, etc. We're also not bound to using the generated proxies -- any interface will do.