Share via


Fechar e anular recursos de liberação com segurança quando as conexões de rede forem descartadas

O exemplo UsingUsing demonstra o uso dos métodos Close e Abort para limpar recursos ao usar um cliente tipado. A instrução using causa exceções quando a conexão de rede não é robusta. Este exemplo se baseia na Introdução que implementa um serviço de calculadora. Nesta amostra, o cliente é um aplicativo de console (.exe) e o serviço é hospedado pelos Serviços de Informações da Internet (IIS).

Observação

O procedimento de instalação e as instruções de compilação dessa amostra estão no final deste tópico.

Este exemplo mostra dois dos problemas comuns que ocorrem ao usar a instrução "using" em C# com clientes tipados, bem como o código que limpa corretamente após exceções.

A instrução "using" em C# resulta em uma chamada para Dispose(). Isso é o mesmo que Close(), que pode gerar exceções quando ocorre um erro de rede. Como a chamada para Dispose() acontece implicitamente na chave de fechamento do bloco "using", essa fonte de exceções provavelmente passará despercebida por pessoas que escrevem o código e lêem o código. Isso representa uma possível fonte de erros de aplicativo.

O primeiro problema, ilustrado no método DemonstrateProblemUsingCanThrow, é que a chave de fechamento gera uma exceção e o código após a chave de fechamento não é executado:

using (CalculatorClient client = new CalculatorClient())
{
    ...
} // <-- this line might throw
Console.WriteLine("Hope this code wasn't important, because it might not happen.");

Mesmo que nada dentro do bloco de uso gere uma exceção ou todas as exceções dentro do bloco de uso sejam capturadas, o Console.WriteLine pode não acontecer porque a chamada implícita Dispose() na chave de fechamento pode gerar uma exceção.

O segundo problema, ilustrado no método DemonstrateProblemUsingCanThrowAndMask, é outra implicação da chave de fechamento gerando uma exceção:

using (CalculatorClient client = new CalculatorClient())
{
    ...
    throw new ApplicationException("Hope this exception was not important, because "+
                                   "it might be masked by the Close exception.");
} // <-- this line might throw an exception.

Como o Dispose() ocorre dentro de um bloco "finally", o ApplicationException nunca será visto fora do bloco de uso se o Dispose() falhar. Se o código externo precisar saber sobre quando o ApplicationException ocorre, o constructo "using" poderá causar problemas mascarando essa exceção.

Por fim, o exemplo demonstra como limpar corretamente quando ocorrem exceções em DemonstrateCleanupWithExceptions. Isso usa um bloco try/catch para relatar erros e chamar Abort. Consulte o exemplo Exceções esperadas para obter mais detalhes sobre como capturar exceções de chamadas de cliente.

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

Observação

A instrução using e o ServiceHost: muitos aplicativos de auto-hospedagem fazem pouco mais do que hospedar um serviço, e o ServiceHost.Close raramente gera uma exceção, de modo que esses aplicativos possam usar com segurança a instrução using com o ServiceHost. No entanto, lembre-se de que o ServiceHost.Close pode gerar um CommunicationException e, portanto, se seu aplicativo continuar após o fechamento do ServiceHost, você deve evitar o uso da instrução e seguir o padrão fornecido anteriormente.

Quando você executa a amostra, as solicitações e respostas da operação são exibidas na janela do console do cliente.

O processo do cliente executa três cenários, e cada um deles tenta chamar Divide. O primeiro cenário demonstra o código sendo ignorado devido a uma exceção de Dispose(). O segundo cenário demonstra uma exceção importante que está sendo mascarada devido a uma exceção de Dispose(). O terceiro cenário demonstra a limpeza correta.

A saída esperada do processo do cliente é:

=
= Demonstrating problem:  closing brace of using statement can throw.
=
Got System.ServiceModel.CommunicationException from Divide.
Got System.ServiceModel.Security.MessageSecurityException
=
= Demonstrating problem:  closing brace of using statement can mask other Exceptions.
=
Got System.ServiceModel.CommunicationException from Divide.
Got System.ServiceModel.Security.MessageSecurityException
=
= Demonstrating cleanup with Exceptions.
=
Calling client.Add(0.0, 0.0);
        client.Add(0.0, 0.0); returned 0
Calling client.Divide(0.0, 0.0);
Got System.ServiceModel.CommunicationException from Divide.

Press <ENTER> to terminate client.

Para configurar, compilar, e executar o exemplo

  1. Verifique se você executou o Procedimento de instalação única para os exemplos do Windows Communication Foundation.

  2. Para compilar a edição .NET do C# ou do Visual Basic da solução, siga as instruções contidas em Como Compilar as Amostras do Windows Communication Foundation.

  3. Para executar a amostra em uma configuração de computador único ou entre computadores, siga as instruções contidas em Como executar as amostras do Windows Communication Foundation.