Мне нравится создавать экземпляры моих клиентов службы WCF в блоке using, поскольку он в значительной степени является стандартным способом использования ресурсов, реализующих IDisposable:
using (var client = new SomeWCFServiceClient()) 
{
    //Do something with the client 
}
Но, как отмечено в этой статье MSDN, обертка WCF-клиента в блоке using может маскировать любые ошибки, которые приводят к клиенту оставаясь в неисправном состоянии (например, тайм-аут или проблема связи). Короче говоря, когда вызывается Dispose(), запускается метод Close() клиента, но выдает ошибку, потому что он в неисправном состоянии. Исходное исключение затем маскируется вторым исключением. Нехорошо.
Предлагаемый обходной путь в статье MSDN заключается в том, чтобы полностью избежать использования блока using и вместо этого создавать экземпляры ваших клиентов и использовать их примерно так:
try
{
    ...
    client.Close();
}
catch (CommunicationException e)
{
    ...
    client.Abort();
}
catch (TimeoutException e)
{
    ...
    client.Abort();
}
catch (Exception e)
{
    ...
    client.Abort();
    throw;
}
По сравнению с блоком using, я считаю это уродливым. И много кода для записи каждый раз, когда вам нужен клиент.
К счастью, я нашел несколько других обходных решений, таких как этот для IServiceOriented. Вы начинаете с:
public delegate void UseServiceDelegate<T>(T proxy); 
public static class Service<T> 
{ 
    public static ChannelFactory<T> _channelFactory = new ChannelFactory<T>(""); 
    public static void Use(UseServiceDelegate<T> codeBlock) 
    { 
        IClientChannel proxy = (IClientChannel)_channelFactory.CreateChannel(); 
        bool success = false; 
        try 
        { 
            codeBlock((T)proxy); 
            proxy.Close(); 
            success = true; 
        } 
        finally 
        { 
            if (!success) 
            { 
                proxy.Abort(); 
            } 
        } 
     } 
} 
Что позволяет:
Service<IOrderService>.Use(orderService => 
{ 
    orderService.PlaceOrder(request); 
}); 
Это неплохо, но я не считаю это выразительным и легко понятным как блок using.
Обходной путь, который я сейчас пытаюсь использовать, я впервые прочитал о blog.davidbarret.net. В основном вы переопределяете клиентский метод Dispose(), где бы вы его ни использовали. Что-то вроде:
public partial class SomeWCFServiceClient : IDisposable
{
    void IDisposable.Dispose() 
    {
        if (this.State == CommunicationState.Faulted) 
        {
            this.Abort();
        } 
        else 
        {
            this.Close();
        }
    }
}
Это, похоже, позволяет снова разрешить блок using без опасности маскировки исключения с ошибкой.
Итак, есть ли какие-либо другие ошибки, которые я должен искать для использования этих обходных решений? Кто-нибудь придумал что-нибудь лучше?
