Qual é a melhor solução alternativa para o cliente WCF `usando` problema de bloco?

Eu gosto de instanciar meus clientes de serviço WCF dentro de umusing, pois é praticamente a maneira padrão de usar recursos que implementamIDisposable:

using (var client = new SomeWCFServiceClient()) 
{
    //Do something with the client 
}

Mas, como observado emeste artigo da MSDN, agrupando um cliente WCF em umusing bloco @ poderia mascarar quaisquer erros que resultassem no cliente sendo deixado em um estado com falha (como um tempo limite ou um problema de comunicação). Para encurtar a história, quando Dispose () é chamado, o método Close () do cliente é acionado, mas gera um erro porque está em um estado com falha. A exceção original é mascarada pela segunda exceção. Não é bom

A solução sugerida no artigo do MSDN é evitar completamente o uso de umusing block e, em vez disso, instanciar seus clientes e usá-los da seguinte maneira:

try
{
    ...
    client.Close();
}
catch (CommunicationException e)
{
    ...
    client.Abort();
}
catch (TimeoutException e)
{
    ...
    client.Abort();
}
catch (Exception e)
{
    ...
    client.Abort();
    throw;
}

Comparado com ousing bloco, acho isso feio. E muito código para escrever sempre que você precisar de um client

Felizmente, encontrei algumas outras soluções alternativas, como esta no IServiceOriented. Você começa com:

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(); 
            } 
        } 
     } 
} 

Que permite:

Service<IOrderService>.Use(orderService => 
{ 
    orderService.PlaceOrder(request); 
}); 

Isso não é ruim, mas não acho que seja tão expressivo e facilmente compreensível quanto ousing quadra

A solução alternativa que estou tentando usar foi a primeira vez que li sobre blog.davidbarret.net. Basicamente, você substitui o @ do clienDispose() método onde quer que você o use. Algo como

public partial class SomeWCFServiceClient : IDisposable
{
    void IDisposable.Dispose() 
    {
        if (this.State == CommunicationState.Faulted) 
        {
            this.Abort();
        } 
        else 
        {
            this.Close();
        }
    }
}

Isso parece permitir que ousing bloqueie novamente sem o perigo de mascarar uma exceção de estado com falh

Então, existem outras dicas que eu tenho que olhar para usar essas soluções alternativas? Alguém sugeriu algo melhor?

questionAnswers(26)

yourAnswerToTheQuestion