Partilhar via


Consumir um serviço Web do Windows Communication Foundation (WCF)

O WCF é a estrutura unificada da Microsoft para a criação de aplicativos orientados a serviços. Ele permite que os desenvolvedores criem aplicativos distribuídos seguros, confiáveis, transacionados e interoperáveis. Este artigo demonstra como consumir um serviço WCF Simple Object Access Protocol (SOAP) de um Xamarin.Forms aplicativo.

WCF descreve um serviço com uma variedade de contratos diferentes, incluindo:

  • Contratos de dados – definem as estruturas de dados que formam a base para o conteúdo de uma mensagem.
  • Contratos de mensagem – compor mensagens de contratos de dados existentes.
  • Contratos de falha – permitem que falhas SOAP personalizadas sejam especificadas.
  • Contratos de serviço – especifique as operações que os serviços oferecem suporte e as mensagens necessárias para interagir com cada operação. Eles também especificam qualquer comportamento de falha personalizado que possa ser associado a operações em cada serviço.

Há diferenças entre ASP.NET ASMX (Web Services) e o WCF, mas o WCF oferece suporte aos mesmos recursos que o ASMX fornece – mensagens SOAP sobre HTTP. Para obter mais informações sobre como consumir um serviço ASMX, consulte Consumir ASP.NET serviços Web (ASMX).

Importante

O suporte da plataforma Xamarin para WCF é limitado a mensagens SOAP codificadas por texto sobre HTTP/HTTPS usando a BasicHttpBinding classe.

O suporte ao WCF requer o uso de ferramentas disponíveis somente em um ambiente Windows para gerar o proxy e hospedar o TodoWCFService. Criar e testar o aplicativo iOS exigirá a implantação do TodoWCFService em um computador Windows ou como um serviço Web do Azure.

Os aplicativos nativos do Xamarin Forms geralmente compartilham código com uma Biblioteca de Classes do .NET Standard. No entanto, o .NET Core atualmente não oferece suporte ao WCF, portanto, o projeto compartilhado deve ser uma biblioteca de classes portátil herdada. Para obter informações sobre o suporte ao WCF no .NET Core, consulte Escolhendo entre o .NET Core e o .NET Framework para aplicativos de servidor.

A solução de aplicativo de exemplo inclui um serviço WCF que pode ser executado localmente e é mostrado na captura de tela a seguir:

Aplicativo de exemplo

Observação

No iOS 9 e superior, o App Transport Security (ATS) impõe conexões seguras entre recursos da Internet (como o servidor back-end do aplicativo) e o aplicativo, evitando assim a divulgação acidental de informações confidenciais. Como o ATS está habilitado por padrão em aplicativos criados para iOS 9, todas as conexões estarão sujeitas aos requisitos de segurança do ATS. Se as conexões não atenderem a esses requisitos, elas falharão com uma exceção.

O ATS pode ser desativado se não for possível usar o protocolo e a HTTPS comunicação segura para recursos da Internet. Isso pode ser feito atualizando o arquivo Info.plist do aplicativo. Para obter mais informações, consulte Segurança de transporte de aplicativo.

Consumir o serviço Web

O serviço WCF fornece as seguintes operações:

Operação Descrição Parâmetros
GetTodoItems Obter uma lista de itens pendentes
CreateTodoItem Criar um novo item de tarefa pendente Um TodoItem serializado XML
EditTodoItem Atualizar um item pendente Um TodoItem serializado XML
DeleteTodoItem Excluir um item pendente Um TodoItem serializado XML

Para obter mais informações sobre o modelo de dados usado no aplicativo, consulte Modelando os dados.

Um proxy deve ser gerado para consumir um serviço WCF, que permite que o aplicativo se conecte ao serviço. O proxy é construído consumindo metadados de serviço que definem os métodos e a configuração de serviço associada. Esses metadados são expostos na forma de um documento WSDL (Web Services Description Language) gerado pelo serviço Web. O proxy pode ser criado usando o Microsoft WCF Web Service Reference Provider no Visual Studio 2017 para adicionar uma referência de serviço para o serviço Web a uma biblioteca do .NET Standard. Uma alternativa para criar o proxy usando o Microsoft WCF Web Service Reference Provider no Visual Studio 2017 é usar a ServiceModel Metadata Utility Tool (svcutil.exe). Para obter mais informações, consulte ServiceModel Metadata Utility Tool (Svcutil.exe).

As classes de proxy geradas fornecem métodos para consumir os serviços Web que usam o padrão de design APM (Modelo de Programação Assíncrona). Nesse padrão, uma operação assíncrona é implementada como dois métodos chamados BeginOperationName e EndOperationName, que começam e terminam a operação assíncrona.

O método BeginOperationName inicia a operação assíncrona e retorna um objeto que implementa a IAsyncResult interface. Depois de chamar BeginOperationName, um aplicativo pode continuar executando instruções no thread de chamada, enquanto a operação assíncrona ocorre em um thread de pool de threads.

Para cada chamada para BeginOperationName, o aplicativo também deve chamar EndOperationName para obter os resultados da operação. O valor de retorno de EndOperationName é o mesmo tipo retornado pelo método de serviço Web síncrono. Por exemplo, o EndGetTodoItems método retorna uma coleção de TodoItem instâncias. O método EndOperationName também inclui um IAsyncResult parâmetro que deve ser definido para a instância retornada pela chamada correspondente para o método BeginOperationName .

A TPL (Biblioteca Paralela de Tarefas) pode simplificar o processo de consumo de um par de métodos de início/fim do APM encapsulando as operações assíncronas no mesmo Task objeto. Esse encapsulamento é fornecido por múltiplas sobrecargas do TaskFactory.FromAsync método.

Para obter mais informações sobre APM, consulte Modelo de programação assíncrona e TPL e programação assíncrona tradicional do .NET Framework no MSDN.

Criar o objeto TodoServiceClient

A classe proxy gerada fornece a TodoServiceClient classe, que é usada para se comunicar com o serviço WCF sobre HTTP. Ele fornece funcionalidade para invocar métodos de serviço Web como operações assíncronas de uma instância de serviço identificada por URI. Para obter mais informações sobre operações assíncronas, consulte Visão geral do suporte assíncrono.

A TodoServiceClient instância é declarada no nível de classe para que o objeto viva pelo tempo que o aplicativo precisar consumir o serviço WCF, conforme mostrado no exemplo de código a seguir:

public class SoapService : ISoapService
{
  ITodoService todoService;
  ...

  public SoapService ()
  {
    todoService = new TodoServiceClient (
      new BasicHttpBinding (),
      new EndpointAddress (Constants.SoapUrl));
  }
  ...
}

A TodoServiceClient instância é configurada com informações de associação e um endereço de ponto de extremidade. Uma associação é usada para especificar os detalhes de transporte, codificação e protocolo necessários para que aplicativos e serviços se comuniquem entre si. O BasicHttpBinding especifica que as mensagens SOAP codificadas em texto serão enviadas pelo protocolo de transporte HTTP. A especificação de um endereço de ponto de extremidade permite que o aplicativo se conecte a diferentes instâncias do serviço WCF, desde que haja várias instâncias publicadas.

Para obter mais informações sobre como configurar a referência de serviço, consulte Configurando a referência de serviço.

Criar objetos de transferência de dados

O aplicativo de exemplo usa a TodoItem classe para modelar dados. Para armazenar um TodoItem item no serviço Web, ele deve primeiro ser convertido para o tipo gerado TodoItem pelo proxy. Isso é realizado pelo ToWCFServiceTodoItem método, conforme mostrado no exemplo de código a seguir:

TodoWCFService.TodoItem ToWCFServiceTodoItem (TodoItem item)
{
  return new TodoWCFService.TodoItem
  {
    ID = item.ID,
    Name = item.Name,
    Notes = item.Notes,
    Done = item.Done
  };
}

Esse método simplesmente cria uma nova TodoWCFService.TodoItem instância e define cada propriedade para a propriedade idêntica da TodoItem instância.

Da mesma forma, quando os dados são recuperados do serviço Web, eles devem ser convertidos do tipo gerado TodoItem pelo proxy em uma TodoItem instância. Isso é realizado com o FromWCFServiceTodoItem método, conforme mostrado no exemplo de código a seguir:

static TodoItem FromWCFServiceTodoItem (TodoWCFService.TodoItem item)
{
  return new TodoItem
  {
    ID = item.ID,
    Name = item.Name,
    Notes = item.Notes,
    Done = item.Done
  };
}

Esse método simplesmente recupera os dados do tipo gerado TodoItem pelo proxy e os define na instância recém-criada TodoItem .

Recuperar dados

Os TodoServiceClient.BeginGetTodoItems métodos e TodoServiceClient.EndGetTodoItems são usados para chamar a GetTodoItems operação fornecida pelo serviço Web. Esses métodos assíncronos são encapsulados em um Task objeto, conforme mostrado no exemplo de código a seguir:

public async Task<List<TodoItem>> RefreshDataAsync ()
{
  ...
  var todoItems = await Task.Factory.FromAsync <ObservableCollection<TodoWCFService.TodoItem>> (
    todoService.BeginGetTodoItems,
    todoService.EndGetTodoItems,
    null,
    TaskCreationOptions.None);

  foreach (var item in todoItems)
  {
    Items.Add (FromWCFServiceTodoItem (item));
  }
  ...
}

O Task.Factory.FromAsync método cria um Task que executa o TodoServiceClient.EndGetTodoItems método depois que o TodoServiceClient.BeginGetTodoItems método é concluído, com o null parâmetro indicando que nenhum dado está sendo passado para o BeginGetTodoItems delegado. Finalmente, o TaskCreationOptions valor da enumeração especifica que o comportamento padrão para a criação e execução de tarefas deve ser usado.

O TodoServiceClient.EndGetTodoItems método retorna um ObservableCollection de TodoWCFService.TodoItem instâncias, que é convertido em um List de TodoItem instâncias para exibição.

Criar fluxo de

Os TodoServiceClient.BeginCreateTodoItem métodos e TodoServiceClient.EndCreateTodoItem são usados para chamar a CreateTodoItem operação fornecida pelo serviço Web. Esses métodos assíncronos são encapsulados em um Task objeto, conforme mostrado no exemplo de código a seguir:

public async Task SaveTodoItemAsync (TodoItem item, bool isNewItem = false)
{
  ...
  var todoItem = ToWCFServiceTodoItem (item);
  ...
  await Task.Factory.FromAsync (
    todoService.BeginCreateTodoItem,
    todoService.EndCreateTodoItem,
    todoItem,
    TaskCreationOptions.None);
  ...
}

O Task.Factory.FromAsync método cria um Task que executa o TodoServiceClient.EndCreateTodoItem método depois que o TodoServiceClient.BeginCreateTodoItem método é concluído, com o todoItem parâmetro sendo os dados que são passados para o BeginCreateTodoItem delegado para especificar o TodoItem a ser criado pelo serviço Web. Finalmente, o TaskCreationOptions valor da enumeração especifica que o comportamento padrão para a criação e execução de tarefas deve ser usado.

O serviço Web lança um FaultException se ele não conseguir criar o TodoItem, que é manipulado pelo aplicativo.

Atualizar dados

Os TodoServiceClient.BeginEditTodoItem métodos e TodoServiceClient.EndEditTodoItem são usados para chamar a EditTodoItem operação fornecida pelo serviço Web. Esses métodos assíncronos são encapsulados em um Task objeto, conforme mostrado no exemplo de código a seguir:

public async Task SaveTodoItemAsync (TodoItem item, bool isNewItem = false)
{
  ...
  var todoItem = ToWCFServiceTodoItem (item);
  ...
  await Task.Factory.FromAsync (
    todoService.BeginEditTodoItem,
    todoService.EndEditTodoItem,
    todoItem,
    TaskCreationOptions.None);
  ...
}

O Task.Factory.FromAsync método cria um Task que executa o TodoServiceClient.EndEditTodoItem método depois que o TodoServiceClient.BeginCreateTodoItem método é concluído, com o todoItem parâmetro sendo os dados que são passados para o BeginEditTodoItem delegado para especificar o TodoItem a ser atualizado pelo serviço Web. Finalmente, o TaskCreationOptions valor da enumeração especifica que o comportamento padrão para a criação e execução de tarefas deve ser usado.

O serviço Web lança um FaultException se ele não conseguir localizar ou atualizar o TodoItem, que é manipulado pelo aplicativo.

Excluir os dados

Os TodoServiceClient.BeginDeleteTodoItem métodos e TodoServiceClient.EndDeleteTodoItem são usados para chamar a DeleteTodoItem operação fornecida pelo serviço Web. Esses métodos assíncronos são encapsulados em um Task objeto, conforme mostrado no exemplo de código a seguir:

public async Task DeleteTodoItemAsync (string id)
{
  ...
  await Task.Factory.FromAsync (
    todoService.BeginDeleteTodoItem,
    todoService.EndDeleteTodoItem,
    id,
    TaskCreationOptions.None);
  ...
}

O Task.Factory.FromAsync método cria um Task que executa o TodoServiceClient.EndDeleteTodoItem método depois que o TodoServiceClient.BeginDeleteTodoItem método é concluído, com o id parâmetro sendo os dados que são passados para o BeginDeleteTodoItem delegado para especificar o TodoItem a ser excluído pelo serviço Web. Finalmente, o TaskCreationOptions valor da enumeração especifica que o comportamento padrão para a criação e execução de tarefas deve ser usado.

O serviço Web lança um FaultException se ele não conseguir localizar ou excluir o TodoItem, que é manipulado pelo aplicativo.

Configurar o acesso remoto ao IIS Express

No Visual Studio 2017 ou Visual Studio 2019, você deve ser capaz de testar o aplicativo UWP em um PC sem configuração adicional. O teste de clientes Android e iOS pode exigir as etapas adicionais nesta seção. Consulte Conectar-se a serviços Web locais a partir de simuladores iOS e emuladores Android para obter mais informações.

Por padrão, o IIS Express só responderá a solicitações para localhosto . Dispositivos remotos (como um dispositivo Android, um iPhone ou até mesmo um simulador) não terão acesso ao seu serviço WCF local. Você precisará saber o endereço IP da estação de trabalho Windows 10 na rede local. Para a finalidade deste exemplo, suponha que sua estação de trabalho tenha o endereço 192.168.1.143IP . As etapas a seguir explicam como configurar o Windows 10 e o IIS Express para aceitar conexões remotas e se conectar ao serviço a partir de um dispositivo físico ou virtual:

  1. Adicione uma exceção ao Firewall do Windows. Você deve abrir uma porta por meio do Firewall do Windows que os aplicativos em sua sub-rede possam usar para se comunicar com o serviço WCF. Crie uma regra de entrada abrindo a porta 49393 no firewall. Em um prompt de comando administrativo, execute este comando:

    netsh advfirewall firewall add rule name="TodoWCFService" dir=in protocol=tcp localport=49393 profile=private remoteip=localsubnet action=allow
    
  2. Configure o IIS Express para aceitar conexões remotas. Você pode configurar o IIS Express editando o arquivo de configuração do IIS Express em [solution directory].vs\config\applicationhost.config. Localize o site elemento com o nome TodoWCFService. Ele deve ser semelhante ao seguinte XML:

    <site name="TodoWCFService" id="2">
        <application path="/" applicationPool="Clr4IntegratedAppPool">
            <virtualDirectory path="/" physicalPath="C:\Users\tom\TodoWCF\TodoWCFService\TodoWCFService" />
        </application>
        <bindings>
            <binding protocol="http" bindingInformation="*:49393:localhost" />
        </bindings>
    </site>
    

    Você precisará adicionar dois binding elementos para abrir a porta 49393 para o tráfego externo e o emulador do Android. A associação usa um [IP address]:[port]:[hostname] formato que especifica como o IIS Express responderá às solicitações. As solicitações externas terão nomes de host que devem ser especificados como um bindingarquivo . Adicione o seguinte XML ao bindings elemento , substituindo o endereço IP pelo seu próprio endereço IP:

    <binding protocol="http" bindingInformation="*:49393:192.168.1.143" />
    <binding protocol="http" bindingInformation="*:49393:127.0.0.1" />
    

    Após as alterações, o bindings elemento deve ter a seguinte aparência:

    <site name="TodoWCFService" id="2">
        <application path="/" applicationPool="Clr4IntegratedAppPool">
            <virtualDirectory path="/" physicalPath="C:\Users\tom\TodoWCF\TodoWCFService\TodoWCFService" />
        </application>
        <bindings>
            <binding protocol="http" bindingInformation="*:49393:localhost" />
            <binding protocol="http" bindingInformation="*:49393:192.168.1.143" />
            <binding protocol="http" bindingInformation="*:49393:127.0.0.1" />
        </bindings>
    </site>
    

    Importante

    Por padrão, o IIS Express não aceitará conexões de fontes externas por motivos de segurança. Para habilitar conexões de dispositivos remotos, você deve executar o IIS Express com permissões administrativas. A maneira mais fácil de fazer isso é executar o Visual Studio 2017 com permissões administrativas. Isso iniciará o IIS Express com permissões administrativas ao executar o TodoWCFService.

    Com essas etapas concluídas, você deve ser capaz de executar o TodoWCFService e conectar-se a partir de outros dispositivos em sua sub-rede. Você pode testar isso executando seu aplicativo e visitando http://localhost:49393/TodoService.svco . Se você receber um erro de solicitação incorreta ao visitar essa URL, você bindings pode estar incorreto na configuração do IIS Express (a solicitação está atingindo o IIS Express, mas está sendo rejeitada). Se você receber um erro diferente, pode ser que seu aplicativo não esteja em execução ou seu firewall esteja configurado incorretamente.

    Para permitir que o IIS Express continue executando e servindo o serviço, desative a opção Editar e Continuar em Depuradores da Web > de Propriedades > do Projeto.

  3. Personalize os dispositivos de ponto de extremidade usados para acessar o serviço. Esta etapa envolve a configuração do aplicativo cliente, em execução em um dispositivo físico ou emulado, para acessar o serviço WCF.

    O emulador Android utiliza um proxy interno que impede que o emulador acesse diretamente o endereço da localhost máquina host. Em vez disso, o endereço 10.0.2.2 no emulador é roteado para localhost na máquina host por meio de um proxy interno. Essas solicitações por proxy terão 127.0.0.1 como nome de host no cabeçalho da solicitação, e é por isso que você criou a associação do IIS Express para esse nome de host nas etapas acima.

    O Simulador do iOS é executado em um host de compilação do Mac, mesmo se você estiver usando o Simulador do iOS Remoto para Windows. As solicitações de rede do simulador terão o IP da estação de trabalho na rede local como o nome do host (neste exemplo, é 192.168.1.143, mas seu endereço IP real provavelmente será diferente). É por isso que você criou a associação do IIS Express para esse nome de host nas etapas acima.

    Verifique se a SoapUrlpropriedade no arquivo Constants.cs no projeto TodoWCF (portátil) tem valores corretos para sua rede:

    public static string SoapUrl
    {
        get
        {
            var defaultUrl = "http://localhost:49393/TodoService.svc";
    
            if (Device.RuntimePlatform == Device.Android)
            {
                defaultUrl = "http://10.0.2.2:49393/TodoService.svc";
            }
            else if (Device.RuntimePlatform == Device.iOS)
            {
                defaultUrl = "http://192.168.1.143:49393/TodoService.svc";
            }
    
            return defaultUrl;
        }
    }
    

    Depois de configurar o Constants.cs com os pontos de extremidade apropriados, você deve ser capaz de se conectar ao TodoWCFService em execução em sua estação de trabalho Windows 10 a partir de dispositivos físicos ou virtuais.