Usando um cliente para acessar um serviço

Os aplicativos cliente devem criar, configurar e usar objetos de cliente ou canal do WCF para se comunicar com os serviços. O tópico Visão geral do cliente WCF fornece uma visão geral dos objetos e etapas envolvidos na criação de objetos básicos do cliente e do canal e no uso deles.

Este tópico fornece informações detalhadas sobre alguns dos problemas com aplicativos cliente e objetos de canal e de cliente que podem ser úteis dependendo do seu cenário.

Visão geral

Este tópico descreve o comportamento e os problemas relacionados a:

  • Tempos de vida do canal e da sessão.

  • Tratar exceções.

  • Noções básicas sobre problemas de bloqueio.

  • Inicializar canais interativamente.

Tempos de vida do canal e da sessão

Os aplicativos WCF (Windows Communication Foundation) incluem duas categorias de canais: datagrama e com sessão.

Um canal de datagrama é um canal no qual nenhuma mensagem está correlacionada. Com um canal de datagrama, se uma operação de entrada ou saída falhar, a próxima operação normalmente não será afetada e o mesmo canal poderá ser reutilizado. Por isso, os canais de datagrama normalmente não falham.

No entanto, os canais com sessão são canais com uma conexão com o outro ponto de extremidade. As mensagens em uma sessão de um lado são sempre correlacionadas com a mesma sessão do outro lado. Além disso, ambos os participantes de uma sessão devem concordar que os requisitos de sua conversa foram atendidos para que essa sessão seja considerada bem-sucedida. Se eles não puderem concordar, o canal com sessão poderá falhar.

Abra clientes explicitamente ou implicitamente chamando a primeira operação.

Observação

Tentar detectar explicitamente canais com sessão com falha normalmente não é útil, pois o momento em que você é notificado depende da implementação da sessão. Por exemplo, como o System.ServiceModel.NetTcpBinding (com a sessão confiável desabilitada) é exibida a sessão da conexão TCP, se você ouvir o evento ICommunicationObject.Faulted no serviço ou o cliente, provavelmente será notificado rapidamente em caso de falha de rede. Mas as sessões confiáveis (estabelecidas por associações nas quais o System.ServiceModel.Channels.ReliableSessionBindingElement está habilitado) são projetadas para isolar os serviços de pequenas falhas de rede. Se a sessão puder ser restabelecida dentro de um período razoável, a mesma associação, configurada para sessões confiáveis, poderá não falhar até que a interrupção continue por um período mais longo.

A maioria das associações fornecidas pelo sistema (que expõem canais à camada do aplicativo) usam sessões por padrão, mas System.ServiceModel.BasicHttpBinding não. Para obter mais informações, confira Usar sessões.

O uso adequado de sessões

As sessões fornecem uma maneira de saber se toda a troca de mensagens foi concluída e se ambos os lados consideraram-na bem-sucedida. É recomendável que um aplicativo de chamada abra o canal, use e feche-o dentro de um bloco try. Se um canal de sessão estiver aberto e o método ICommunicationObject.Close for chamado uma vez e essa chamada retornar com êxito, a sessão será bem-sucedida. Bem-sucedido, nesse caso, significa que todas as garantias de entrega especificadas foram atendidas e o outro lado não chamou ICommunicationObject.Abort no canal antes de chamar Close.

A seção a seguir fornece um exemplo dessa abordagem de cliente.

Tratando exceções

Tratar exceções em aplicativos cliente é simples. Se um canal for aberto, usado e fechado dentro de um bloco try, a conversa terá êxito, a menos que uma exceção seja lançada. Normalmente, se uma exceção for lançada, a conversa será anulada.

Observação

O uso da instrução using (Using no Visual Basic) não é recomendado. Isso ocorre porque o final da instrução using pode causar exceções que podem mascarar outras exceções que talvez você precise saber. Para obter mais informações, consulte Usar Fechar e Anular para liberar recursos de cliente WCF.

O exemplo de código a seguir mostra o padrão de cliente recomendado usando um bloco try/catch e não a instrução using.

using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using Microsoft.WCF.Documentation;

public class Client
{
  public static void Main()
  {
    // Picks up configuration from the config file.
    SampleServiceClient wcfClient = new SampleServiceClient();
    try
    {
      // Making calls.
      Console.WriteLine("Enter the greeting to send: ");
      string greeting = Console.ReadLine();
      Console.WriteLine("The service responded: " + wcfClient.SampleMethod(greeting));

      Console.WriteLine("Press ENTER to exit:");
      Console.ReadLine();

      // Done with service.
      wcfClient.Close();
      Console.WriteLine("Done!");
    }
    catch (TimeoutException timeProblem)
    {
      Console.WriteLine("The service operation timed out. " + timeProblem.Message);
      Console.ReadLine();
      wcfClient.Abort();
    }
    catch (FaultException<GreetingFault> greetingFault)
    {
      Console.WriteLine(greetingFault.Detail.Message);
      Console.ReadLine();
      wcfClient.Abort();
    }
    catch (FaultException unknownFault)
    {
      Console.WriteLine("An unknown exception was received. " + unknownFault.Message);
      Console.ReadLine();
      wcfClient.Abort();
    }
    catch (CommunicationException commProblem)
    {
      Console.WriteLine("There was a communication problem. " + commProblem.Message + commProblem.StackTrace);
      Console.ReadLine();
      wcfClient.Abort();
    }
  }
}

Imports System.ServiceModel
Imports System.ServiceModel.Channels
Imports Microsoft.WCF.Documentation

Public Class Client
    Public Shared Sub Main()
        ' Picks up configuration from the config file.
        Dim wcfClient As New SampleServiceClient()
        Try
            ' Making calls.
            Console.WriteLine("Enter the greeting to send: ")
            Dim greeting As String = Console.ReadLine()
            Console.WriteLine("The service responded: " & wcfClient.SampleMethod(greeting))

            Console.WriteLine("Press ENTER to exit:")
            Console.ReadLine()

            ' Done with service. 
            wcfClient.Close()
            Console.WriteLine("Done!")
        Catch timeProblem As TimeoutException
            Console.WriteLine("The service operation timed out. " & timeProblem.Message)
            Console.ReadLine()
            wcfClient.Abort()
        Catch greetingFault As FaultException(Of GreetingFault)
            Console.WriteLine(greetingFault.Detail.Message)
            Console.ReadLine()
            wcfClient.Abort()
        Catch unknownFault As FaultException
            Console.WriteLine("An unknown exception was received. " & unknownFault.Message)
            Console.ReadLine()
            wcfClient.Abort()
        Catch commProblem As CommunicationException
            Console.WriteLine("There was a communication problem. " & commProblem.Message + commProblem.StackTrace)
            Console.ReadLine()
            wcfClient.Abort()
        End Try
    End Sub
End Class

Observação

Verificar o valor da propriedade ICommunicationObject.State é uma condição de corrida e não é recomendável determinar se deseja reutilizar ou fechar um canal.

Os canais de datagrama nunca falham mesmo que ocorram exceções quando são fechados. Além disso, clientes não duplex que não conseguem se autenticar usando uma conversa segura normalmente lançam um System.ServiceModel.Security.MessageSecurityException. No entanto, se o cliente duplex que usa uma conversa segura não se autenticar, o cliente receberá um System.TimeoutException em vez disso.

Para obter informações mais completas sobre como trabalhar com informações de erro no nível do aplicativo, consulte Especificar e tratar falhas em contratos e serviços. Exceções esperadas descreve exceções esperadas e mostra como tratá-las. Para obter mais informações sobre como tratar erros ao desenvolver canais, consulte Tratamento de exceções e falhas.

Bloqueio e desempenho do cliente

Quando um aplicativo chama de forma síncrona uma operação de solicitação-resposta, o cliente é bloqueado até que um valor retornado seja recebido ou uma exceção (como um System.TimeoutException) seja gerada. Esse comportamento é semelhante o comportamento local. Quando um aplicativo invoca de forma síncrona uma operação em um objeto ou canal do cliente WCF, o cliente não retorna até que a camada de canal possa gravar os dados na rede ou até que uma exceção seja lançada. E, embora o padrão de troca de mensagens unidirecional (especificado marcando uma operação com OperationContractAttribute.IsOneWay definida como true) possa tornar alguns clientes mais responsivos, as operações unidirecionais também podem ser bloqueadas, dependendo da associação e de quais mensagens já foram enviadas. As operações unidirecionais são apenas sobre a troca de mensagens, nem mais nem menos. Para obter mais informações, consulte Serviços unidirecionais.

Partes de dados grandes podem atrasar o processamento do cliente, sem importar o padrão de troca de mensagens. Para entender como lidar com esses problemas, consulte Dados grandes e streaming.

Se o aplicativo precisar trabalhar mais enquanto uma operação for concluída, você deverá criar um par de métodos assíncronos na interface do contrato de serviço implementada pelo cliente WCF. A maneira mais fácil de fazer isso é usar a opção /async na Ferramenta de utilitário de metadados do ServiceModel (Svcutil.exe). Para ver um exemplo, confira Como chamar operações de serviço de forma assíncrona.

Para obter mais informações sobre como aumentar o desempenho do cliente, consulte Aplicativos cliente de camada intermediária.

Habilitar o usuário a selecionar credenciais dinamicamente

A interface IInteractiveChannelInitializer permite que os aplicativos exibam uma interface do usuário que permite que o usuário escolha credenciais com as quais um canal é criado antes do início dos temporizadores de tempo limite.

Os desenvolvedores de aplicativos podem usar um IInteractiveChannelInitializer inserido de duas maneiras. O aplicativo cliente pode chamar ClientBase<TChannel>.DisplayInitializationUI ou IClientChannel.DisplayInitializationUI (ou uma versão assíncrona) antes de abrir o canal (abordagem explícita) ou chamar a primeira operação (abordagem implícita).

Se estiver usando a abordagem implícita, o aplicativo deverá chamar a primeira operação em uma extensão ClientBase<TChannel> ou IClientChannel. Se ele chamar algo diferente da primeira operação, uma exceção será lançada.

Se estiver usando a abordagem explícita, o aplicativo deverá executar as seguintes etapas na ordem:

  1. Chame ClientBase<TChannel>.DisplayInitializationUI ou IClientChannel.DisplayInitializationUI (ou uma versão assíncrona).

  2. Quando os inicializadores tiverem retornado, chame o método Open no objeto IClientChannel ou no objeto IClientChannel retornado da propriedade ClientBase<TChannel>.InnerChannel.

  3. Chamar as operações.

É recomendável que os aplicativos de qualidade de produção controlem o processo de interface do usuário adotando a abordagem explícita.

Aplicativos que usam a abordagem implícita invocam os inicializadores de interface do usuário, mas se o usuário do aplicativo não responder dentro do período de tempo limite de envio da associação, uma exceção será gerada quando a interface do usuário retornar.

Confira também