Introdução aos serviços Web
Este guia demonstra como consumir diferentes tecnologias de serviço Web. Os tópicos abordados incluem comunicação com serviços REST, serviços SOAP e serviços do Windows Communication Foundation.
Para funcionar corretamente, muitos aplicativos móveis dependem da nuvem e, portanto, a integração de serviços Web em aplicativos móveis é um cenário comum. A plataforma Xamarin dá suporte ao consumo de diferentes tecnologias de serviço Web e inclui suporte interno e de terceiros para consumir serviços RESTful, ASMX e WCF (Windows Communication Foundation).
Para clientes que usam o Xamarin.Forms, há exemplos completos usando cada uma dessas tecnologias na documentação dos Serviços Web do Xamarin.Forms .
Importante
No iOS 9, a ATS (Segurança de Transporte de Aplicativo) impõe conexões seguras entre recursos da Internet (como o servidor de back-end do aplicativo) e o aplicativo, impedindo assim a divulgação acidental de informações confidenciais. Como o ATS é 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.
Você poderá recusar a ATS se não for possível usar o HTTPS
protocolo e a 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 do Transporte de Aplicativo.
REST
REST (Transferência de Estado Representacional) é um estilo de arquitetura para a criação de serviços Web. As solicitações REST são feitas por HTTP usando os mesmos verbos HTTP que os navegadores da Web usam para recuperar páginas da Web e enviar dados para os servidores. Os verbos são:
- GET – essa operação é usada para recuperar dados do serviço Web.
- POST – essa operação é usada para criar um item de dados no serviço Web.
- PUT – essa operação é usada para atualizar um item de dados no serviço Web.
- PATCH – essa operação é usada para atualizar um item de dados no serviço Web, descrevendo um conjunto de instruções sobre como o item deve ser modificado. Esse verbo não é usado no aplicativo de exemplo.
- DELETE – essa operação é usada para excluir um item de dados no serviço Web.
APIs de serviço Web que aderem ao REST são chamadas de APIs RESTful e são definidas usando:
- Um URI de base.
- Métodos HTTP, como GET, POST, PUT, PATCH ou DELETE.
- Um tipo de mídia para os dados, como JavaScript Object Notation (JSON).
A simplicidade do REST ajudou a torná-lo o método principal para acessar serviços Web em aplicativos móveis.
Consumindo serviços REST
Há várias bibliotecas e classes que podem ser usadas para consumir serviços REST e as subseções a seguir as discutem. Para obter mais informações sobre como consumir um serviço REST, consulte Consumir um serviço Web RESTful.
HttpClient
As Bibliotecas de Cliente HTTP da Microsoft fornecem a HttpClient
classe , que é usada para enviar e receber solicitações por HTTP. Ele fornece funcionalidade para enviar solicitações HTTP e receber respostas HTTP de um recurso identificado pelo URI. Cada solicitação é enviada como uma operação assíncrona. Para obter mais informações sobre operações assíncronas, consulte Visão geral do suporte assíncrono.
A HttpResponseMessage
classe representa uma mensagem de resposta HTTP recebida do serviço Web depois que uma solicitação HTTP é feita. Ele contém informações sobre a resposta, incluindo o código status, cabeçalhos e corpo. A HttpContent
classe representa o corpo HTTP e os cabeçalhos de conteúdo, como Content-Type
e Content-Encoding
. O conteúdo pode ser lido usando qualquer um dos ReadAs
métodos, como ReadAsStringAsync
e ReadAsByteArrayAsync
, dependendo do formato dos dados.
Para obter mais informações sobre a HttpClient
classe , consulte Criando o objeto HTTPClient.
HTTPWebRequest
Chamar serviços Web com HTTPWebRequest
envolve:
- Criando a instância de solicitação para um URI específico.
- Definindo várias propriedades HTTP na instância de solicitação.
- Recuperando um
HttpWebResponse
da solicitação. - Lendo dados da resposta.
Por exemplo, o código a seguir recupera dados do serviço Web da Biblioteca Nacional de Medicina dos EUA:
var rxcui = "198440";
var request = HttpWebRequest.Create(string.Format(@"https://rxnav.nlm.nih.gov/REST/RxTerms/rxcui/{0}/allinfo", rxcui));
request.ContentType = "application/json";
request.Method = "GET";
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
if (response.StatusCode != HttpStatusCode.OK)
Console.Out.WriteLine("Error fetching data. Server returned status code: {0}", response.StatusCode);
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
var content = reader.ReadToEnd();
if(string.IsNullOrWhiteSpace(content)) {
Console.Out.WriteLine("Response contained empty body...");
}
else {
Console.Out.WriteLine("Response Body: \r\n {0}", content);
}
Assert.NotNull(content);
}
}
O exemplo acima cria um HttpWebRequest
que retornará dados formatados como JSON. Os dados são retornados em um HttpWebResponse
, do qual um StreamReader
pode ser obtido para ler os dados.
RestSharp
Outra abordagem para consumir serviços REST é usar a biblioteca RestSharp . RestSharp encapsula solicitações HTTP, incluindo suporte para recuperar resultados como conteúdo de cadeia de caracteres bruto ou como um objeto C# desserializado. Por exemplo, o código a seguir faz uma solicitação para o serviço Web da Biblioteca Nacional de Medicina dos EUA e recupera os resultados como uma cadeia de caracteres formatada em JSON:
var request = new RestRequest(string.Format("{0}/allinfo", rxcui));
request.RequestFormat = DataFormat.Json;
var response = Client.Execute(request);
if(string.IsNullOrWhiteSpace(response.Content) || response.StatusCode != System.Net.HttpStatusCode.OK) {
return null;
}
rxTerm = DeserializeRxTerm(response.Content);
DeserializeRxTerm
é um método que pegará a cadeia de caracteres JSON bruta da propriedade e a RestSharp.RestResponse.Content
converterá em um objeto C#. A desserialização dos dados retornados dos serviços Web é discutida posteriormente neste artigo.
Nsurlconnection
Além das classes disponíveis na BCL (biblioteca de classes base) Mono, como HttpWebRequest
, e bibliotecas C# de terceiros, como RestSharp, classes específicas da plataforma também estão disponíveis para consumir serviços Web. Por exemplo, no iOS, as NSUrlConnection
classes e NSMutableUrlRequest
podem ser usadas.
O exemplo de código a seguir mostra como chamar o serviço Web da Biblioteca Nacional de Medicina dos EUA usando classes iOS:
var rxcui = "198440";
var request = new NSMutableUrlRequest(new NSUrl(string.Format("https://rxnav.nlm.nih.gov/REST/RxTerms/rxcui/{0}/allinfo", rxcui)),
NSUrlRequestCachePolicy.ReloadRevalidatingCacheData, 20);
request["Accept"] = "application/json";
var connectionDelegate = new RxTermNSURLConnectionDelegate();
var connection = new NSUrlConnection(request, connectionDelegate);
connection.Start();
public class RxTermNSURLConnectionDelegate : NSUrlConnectionDelegate
{
StringBuilder _ResponseBuilder;
public bool IsFinishedLoading { get; set; }
public string ResponseContent { get; set; }
public RxTermNSURLConnectionDelegate()
: base()
{
_ResponseBuilder = new StringBuilder();
}
public override void ReceivedData(NSUrlConnection connection, NSData data)
{
if(data != null) {
_ResponseBuilder.Append(data.ToString());
}
}
public override void FinishedLoading(NSUrlConnection connection)
{
IsFinishedLoading = true;
ResponseContent = _ResponseBuilder.ToString();
}
}
Em geral, classes específicas da plataforma para consumir serviços Web devem ser limitadas a cenários em que o código nativo está sendo portado para C#. Sempre que possível, o código de acesso do serviço Web deve ser portátil para que possa ser compartilhado entre plataformas.
ServiceStack
Outra opção para chamar serviços Web é a biblioteca da Pilha de Serviços . Por exemplo, o código a seguir mostra como usar o método do IServiceClient.GetAsync
Service Stack para emitir uma solicitação de serviço:
client.GetAsync<CustomersResponse>("",
(response) => {
foreach(var c in response.Customers) {
Console.WriteLine(c.CompanyName);
}
},
(response, ex) => {
Console.WriteLine(ex.Message);
});
Importante
Embora ferramentas como ServiceStack e RestSharp facilitem chamar e consumir serviços REST, às vezes não é trivial consumir XML ou JSON que não está em conformidade com as convenções de serialização padrão do DataContract . Se necessário, invoque a solicitação e manipule a serialização apropriada explicitamente usando a biblioteca ServiceStack.Text discutida abaixo.
Consumindo dados RESTful
Os serviços Web RESTful normalmente usam mensagens JSON para retornar dados ao cliente. JSON é um formato de intercâmbio de dados baseado em texto que produz cargas compactas, o que resulta em requisitos de largura de banda reduzidos ao enviar dados. Nesta seção, os mecanismos para consumir respostas RESTful em JSON e POX (Plain-Old-XML) serão examinados.
System.JSON
A plataforma Xamarin é fornecida com suporte para JSON pronto para uso. Usando um JsonObject
, os resultados podem ser recuperados conforme mostrado no exemplo de código a seguir:
var obj = JsonObject.Parse(json);
var properties = obj["rxtermsProperties"];
term.BrandName = properties["brandName"];
term.DisplayName = properties["displayName"];
term.Synonym = properties["synonym"];
term.FullName = properties["fullName"];
term.FullGenericName = properties["fullGenericName"];
term.Strength = properties["strength"];
No entanto, é importante estar ciente de que as System.Json
ferramentas carregam a totalidade dos dados na memória.
JSON.NET
A biblioteca de JSON.NET NewtonSoft é uma biblioteca amplamente usada para serializar e desserializar mensagens JSON. O exemplo de código a seguir mostra como usar JSON.NET para desserializar uma mensagem JSON em um objeto C#:
var term = new RxTerm();
var properties = JObject.Parse(json)["rxtermsProperties"];
term.BrandName = properties["brandName"].Value<string>();
term.DisplayName = properties["displayName"].Value<string>();
term.Synonym = properties["synonym"].Value<string>();;
term.FullName = properties["fullName"].Value<string>();;
term.FullGenericName = properties["fullGenericName"].Value<string>();;
term.Strength = properties["strength"].Value<string>();
term.RxCUI = properties["rxcui"].Value<string>();
ServiceStack.Text
ServiceStack.Text é uma biblioteca de serialização JSON projetada para funcionar com a biblioteca ServiceStack. O exemplo de código a seguir mostra como analisar JSON usando um ServiceStack.Text.JsonObject
:
var result = JsonObject.Parse(json).Object("rxtermsProperties")
.ConvertTo(x => new RxTerm {
BrandName = x.Get("brandName"),
DisplayName = x.Get("displayName"),
Synonym = x.Get("synonym"),
FullName = x.Get("fullName"),
FullGenericName = x.Get("fullGenericName"),
Strength = x.Get("strength"),
RxTermDoseForm = x.Get("rxtermsDoseForm"),
Route = x.Get("route"),
RxCUI = x.Get("rxcui"),
RxNormDoseForm = x.Get("rxnormDoseForm"),
});
System.Xml.Linq
No caso de consumir um serviço Web REST baseado em XML, LINQ to XML pode ser usado para analisar o XML e preencher um objeto C# embutido, conforme demonstrado no exemplo de código a seguir:
var doc = XDocument.Parse(xml);
var result = doc.Root.Descendants("rxtermsProperties")
.Select(x=> new RxTerm()
{
BrandName = x.Element("brandName").Value,
DisplayName = x.Element("displayName").Value,
Synonym = x.Element("synonym").Value,
FullName = x.Element("fullName").Value,
FullGenericName = x.Element("fullGenericName").Value,
//bind more here...
RxCUI = x.Element("rxcui").Value,
});
SERVIÇO Web ASP.NET (ASMX)
O ASMX fornece a capacidade de criar serviços Web que enviam mensagens usando o SOAP (Simple Object Access Protocol). SOAP é um protocolo independente de plataforma e independente de linguagem para criar e acessar serviços Web. Os consumidores de um serviço ASMX não precisam saber nada sobre a plataforma, o modelo de objeto ou a linguagem de programação usada para implementar o serviço. Eles só precisam entender como enviar e receber mensagens SOAP.
Uma mensagem SOAP é um documento XML que contém os seguintes elementos:
- Um elemento raiz chamado Envelope que identifica o documento XML como uma mensagem SOAP.
- Um elemento Header opcional que contém informações específicas do aplicativo, como dados de autenticação. Se o elemento Header estiver presente, ele deverá ser o primeiro elemento filho do elemento Envelope .
- Um elemento Body necessário que contém a mensagem SOAP destinada ao destinatário.
- Um elemento Fault opcional usado para indicar mensagens de erro. Se o elemento Fault estiver presente, ele deverá ser um elemento filho do elemento Body .
O SOAP pode operar em vários protocolos de transporte, incluindo HTTP, SMTP, TCP e UDP. No entanto, um serviço ASMX só pode operar por HTTP. A plataforma Xamarin dá suporte a implementações soap 1.1 padrão por HTTP, e isso inclui suporte para muitas das configurações de serviço ASMX padrão.
Gerando um proxy
Um proxy deve ser gerado para consumir um serviço ASMX, o 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 como um documento WSDL (Linguagem de Descrição dos Serviços Web) gerado pelo serviço Web. O proxy é criado usando Visual Studio para Mac ou Visual Studio para adicionar uma referência da Web para o serviço Web aos projetos específicos da plataforma.
A URL do serviço Web pode ser uma fonte remota hospedada ou um recurso do sistema de arquivos local acessível por meio do prefixo de file:///
caminho, por exemplo:
file:///Users/myUserName/projects/MyProjectName/service.wsdl
Isso gera o proxy na pasta Referências de Serviço ou Web do projeto. Como um proxy é gerado, ele não deve ser modificado.
Adicionar manualmente um proxy a um projeto
Se você tiver um proxy existente que foi gerado usando ferramentas compatíveis, essa saída poderá ser consumida quando incluída como parte do projeto. Em Visual Studio para Mac, use a opção de menu Adicionar arquivos... para adicionar o proxy. Além disso, isso requer queSystem.Web.Services.dll sejam referenciados explicitamente usando a caixa de diálogo Adicionar Referências... .
Consumindo o proxy
As classes de proxy geradas fornecem métodos para consumir o serviço Web que usa 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 iniciam e encerram 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 sobre o 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 retornado de EndOperationName é o mesmo tipo retornado pelo método de serviço Web síncrono. O código a seguir mostra um exemplo disso:
public async Task<List<TodoItem>> RefreshDataAsync ()
{
...
var todoItems = await Task.Factory.FromAsync<ASMXService.TodoItem[]> (
todoService.BeginGetTodoItems,
todoService.EndGetTodoItems,
null,
TaskCreationOptions.None);
...
}
A TPL (Biblioteca Paralela de Tarefas) pode simplificar o processo de consumo de um par de métodos de início/término do APM encapsulando as operações assíncronas no mesmo Task
objeto. Esse encapsulamento é fornecido por várias sobrecargas do Task.Factory.FromAsync
método . Esse método cria um Task
que executa o TodoService.EndGetTodoItems
método depois que o TodoService.BeginGetTodoItems
método é concluído, com o null
parâmetro indicando que nenhum dado está sendo passado para o BeginGetTodoItems
delegado. Por fim, o valor da TaskCreationOptions
enumeração especifica que o comportamento padrão para a criação e execução de tarefas deve ser usado.
Para obter mais informações sobre o APM, consulte Modelo de Programação Assíncrona e TPL e Programação Assíncrona .NET Framework Tradicional no MSDN.
Para obter mais informações sobre como consumir um serviço ASMX, consulte Consumir um SERVIÇO Web ASP.NET (ASMX).
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.
O WCF descreve um serviço com uma variedade de contratos diferentes que incluem o seguinte:
- Contratos de dados – defina as estruturas de dados que formam a base para o conteúdo dentro de uma mensagem.
- Contratos de mensagens – redigir 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 dão 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 SERVIÇOs Web (ASMX) e WCF, mas é importante entender que o WCF dá suporte aos mesmos recursos que o ASMX fornece – mensagens SOAP por HTTP.
Importante
O suporte da plataforma Xamarin para WCF é limitado a mensagens SOAP codificadas em texto por HTTP/HTTPS usando a BasicHttpBinding
classe . Além disso, o suporte ao WCF requer o uso de ferramentas disponíveis apenas em um ambiente do Windows para gerar o proxy.
Gerando um proxy
Um proxy deve ser gerado para consumir um serviço WCF, o 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 (Linguagem de Descrição dos Serviços Web) gerado pelo serviço Web. O proxy pode ser criado usando o Provedor do Microsoft WCF Web Service Reference no Visual Studio 2017 para adicionar uma referência de serviço para o serviço Web a uma Biblioteca .NET Standard.
Uma alternativa para criar o proxy usando o Provedor do Microsoft WCF Web Service Reference no Visual Studio 2017 é usar a Ferramenta de Utilitário de Metadados serviceModel (svcutil.exe). Para obter mais informações, consulte ServiceModel Metadata Utility Tool (Svcutil.exe).
Configurando o Proxy
A configuração do proxy gerado geralmente terá dois argumentos de configuração (dependendo de SOAP 1.1/ASMX ou WCF) durante a inicialização: as EndpointAddress
informações de associação e/ou associadas, conforme mostrado no exemplo abaixo:
var binding = new BasicHttpBinding () {
Name= "basicHttpBinding",
MaxReceivedMessageSize = 67108864,
};
binding.ReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas() {
MaxArrayLength = 2147483646,
MaxStringContentLength = 5242880,
};
var timeout = new TimeSpan(0,1,0);
binding.SendTimeout= timeout;
binding.OpenTimeout = timeout;
binding.ReceiveTimeout = timeout;
client = new Service1Client (binding, new EndpointAddress ("http://192.168.1.100/Service1.svc"));
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. Especificar 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.
Consumindo o proxy
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 iniciam e encerram 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 sobre o 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 retornado de EndOperationName é o mesmo tipo retornado pelo método de serviço Web síncrono. O código a seguir mostra um exemplo disso:
public async Task<List<TodoItem>> RefreshDataAsync ()
{
...
var todoItems = await Task.Factory.FromAsync <ObservableCollection<TodoWCFService.TodoItem>> (
todoService.BeginGetTodoItems,
todoService.EndGetTodoItems,
null,
TaskCreationOptions.None);
...
}
A TPL (Biblioteca Paralela de Tarefas) pode simplificar o processo de consumo de um par de métodos de início/término do APM encapsulando as operações assíncronas no mesmo Task
objeto. Esse encapsulamento é fornecido por várias sobrecargas do Task.Factory.FromAsync
método . Esse 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. Por fim, o valor da TaskCreationOptions
enumeração especifica que o comportamento padrão para a criação e execução de tarefas deve ser usado.
Para obter mais informações sobre o APM, consulte Modelo de Programação Assíncrona e TPL e Programação Assíncrona .NET Framework Tradicional no MSDN.
Para obter mais informações sobre como consumir um serviço WCF, consulte Consumir um serviço Web do WCF (Windows Communication Foundation).
Usando a segurança de transporte
Os Serviços do WCF podem empregar segurança em nível de transporte para proteger contra interceptação de mensagens. A plataforma Xamarin dá suporte a associações que empregam segurança em nível de transporte usando SSL. No entanto, pode haver casos em que a pilha pode precisar validar o certificado, o que resulta em um comportamento imprevisto. A validação pode ser substituída registrando um ServerCertificateValidationCallback
delegado antes de invocar o serviço, conforme demonstrado no exemplo de código a seguir:
System.Net.ServicePointManager.ServerCertificateValidationCallback +=
(se, cert, chain, sslerror) => { return true; };
Isso mantém a criptografia de transporte ignorando a validação do certificado do lado do servidor. No entanto, essa abordagem ignora efetivamente as preocupações de confiança associadas ao certificado e pode não ser apropriada. Para obter mais informações, consulte Usando raízes confiáveis respeitosamente em mono-project.com.
Usando a Segurança de Credencial do Cliente
Os serviços do WCF também podem exigir que os clientes de serviço se autentiquem usando credenciais. A plataforma Xamarin não dá suporte ao protocolo WS-Security, que permite que os clientes enviem credenciais dentro do envelope de mensagem SOAP. No entanto, a plataforma Xamarin dá suporte à capacidade de enviar credenciais de Autenticação Básica HTTP para o servidor especificando o apropriado ClientCredentialType
:
basicHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
Em seguida, as credenciais básicas de autenticação podem ser especificadas:
client.ClientCredentials.UserName.UserName = @"foo";
client.ClientCredentials.UserName.Password = @"mrsnuggles";
Para obter mais informações sobre a autenticação básica HTTP, embora no contexto de um serviço Web REST, consulte Autenticando um serviço Web RESTful.