O advento da Internet e de tecnologias como Web Services e XML transformou, sem sombra de dúvidas, a forma como diferentes sistemas e companhias compartilham informações. Tais avanços possibilitaram não apenas a transferência de dados em tempo real entre aplicações, como também tornaram mais ágeis processos vitais aos mais diversos segmentos. Tudo isto foi fundamental para garantir a sobrevivência de organizações, sobretudo levando em conta um ambiente de negócios sujeito a mudanças drásticas e repentinas.
Um dos primeiros modelos utilizados por Web Services para o intercâmbio de informações foi o padrão SOAP (sigla do inglês “Simple Object Access Protocol”). Por ser baseado em XML, este formato possibilitou a interoperabilidade entre aplicações concebidas em plataformas bastante heterogêneas. A existência de uma especificação comum e amplamente aceita garante que serviços criados em .NET e Java, apenas para citar alguns exemplos, possam ser consumidos em aplicações construídas nas mais diferentes plataformas.
O .NET conta, desde as suas primeiras versões, com um excelente suporte para a construção de Web Services em compatíveis com o padrão SOAP. O lançamento da tecnologia WCF (Windows Communication Foundation) a partir do .NET Framework 3.5 trouxe uma nova proposta para a implementação de serviços, em que foi possível a construção de soluções não apenas seguindo o formato SOAP, como também capazes de suportar outros protocolos como TCP e MSMQ (Microsoft Message Queuing), por exemplo.
Apesar de SOAP atender aos mais variados tipos de demandas, nos últimos tempos uma nova abordagem para a construção de Web Services vem ganhando força. Trata-se do modelo arquitetural conhecido como REST (sigla em inglês para “Representational State Transfer”), em que recursos são representados por meio de um endereço único, utilizando para isto de URLs:
- Dados consumidos por uma aplicação sob a forma de objetos representam exemplos de recursos. Tais informações podem estar no formato JSON ou ainda, no padrão XML;
- Um endereço único, por sua vez, é constituído por informações de identificação do recurso no serviço responsável por prover o mesmo;
- Uma requisição enviada a um serviço conta ainda com uma indicação da operação (uma solicitação HTTP, como GET, POST, PUT ou DELETE) que se deseja efetuar sobre tal recurso.
Serviços em conformidade com o modelo REST também são conhecidos como RESTful Web Services. A tecnologia WCF (Windows Communication Foundation) foi uma das primeiras alternativas na plataforma .NET a possibilitar a construção de soluções seguindo a arquitetura REST.
Embora WCF se destaque por sua grande flexibilidade (suportando diferentes padrões, como já citado), a implementação de serviços RESTful nesta tecnologia costuma requerer um esforço adicional no que se refere à configuração dos diferentes componentes de uma aplicação. Procurando simplificar o desenvolvimento de novas soluções baseadas em REST, a Microsoft lançaria em 2012 um novo modelo que simplificaria a criação de projetos aplicando esta arquitetura: trata-se do ASP.NET Web API.
O Web API é mais um dos frameworks que integra a tecnologia ASP.NET, empregando um modelo de programação similar àquele disponibilizado pelo ASP.NET MVC para a construção de Web sites (e que dispensa muito do trabalho envolvendo configurações que está associado ao uso de WCF). Na prática, isto acontece através da definição de Controllers e Actions: estas construções serão responsáveis pelo tratamento de requisições HTTP enviadas por aplicações que dependam da solução em questão.
Este artigo tem por objetivo demonstrar como acontece a implementação de serviços em Web API, a partir do Visual Studio 2013. Tal meta será alcançada por meio da construção de dois Web Services que utilizam a versão 2.2 do framework ASP.NET Web API.
Exemplo de utilização do framework Web API
Para implementar a solução aqui demonstrada foram utilizados os seguintes recursos:
- O Microsoft Visual Studio Professional 2013 Update 2 como IDE de desenvolvimento;
- O .NET Framework 4.5.1;
- O framework ASP.NET Web API 2.2 para a criação de serviços RESTful.
O exemplo em questão é uma adaptação de uma solução que apresentei no seguinte artigo://www.devmedia.com.br/integracao-wcf-x-jquery-acessando-web-services-via-javascript/28039
A Solution abordada neste novo post prevê a criação de serviços que irão retornar os totais anuais de exportações e importações, considerando para isto as operações comerciais de uma empresa fictícia nos anos de 2012 e 2013. Tais informações referentes ao balanço comercial poderão estar agrupadas por país ou continente.
Criando a solução de exemplo
A fim de iniciar a construção da aplicação de testes proposta por este artigo, será necessário criar primeiramente uma Solution no Visual Studio chamada TesteWebAPI.
A solução mencionada será formada pelo projeto TesteWebAPI.Services: nesta aplicação serão implementados os serviços Web API que possibilitarão o acesso a informações de exportações e exportações de países e continentes, considerando para isto o balanço comercial de uma companhia hipotética num determinado ano.
Na Tabela 1 estão listados os formatos esperados para as URLs de acesso aos Web Services do projeto TesteWebAPI.Services. A sequência de texto “endereco-site” corresponde ao local em que a aplicação Web API será hospedada (endereço este variável), ao passo que “{ano}” indica o período (ano) a ser tomado como base para a obtenção dos dados com o balanço comercial.
Web Service |
Padrão da URL |
Balanço Comercial por País |
http://endereco-site/balanco/paises/{ano} |
Balanço Comercial por Continente |
http://endereco-site/balanco/continentes/{ano} |
Tabela 1. URLs de acesso aos serviços do projeto TesteWebAPI.Services
Implementando os serviços Web API para testes
O primeiro passo envolvendo a construção da solução proposta por este artigo será a criação do projeto TesteWebAPI.Services. Esta aplicação será do tipo “ASP.NET Web Application” (conforme indicado na Figura 1), devendo ser gerada a partir da seleção do template “Web API” e sem a utilização de mecanismos de autenticação (Figura 2).
Figura 1. Criando uma ASP.NET Web Application no Visual Studio 2013
Figura 2. Selecionando o template para a criação de uma Web Application
Na Listagem 1 está a implementação das classes BalancoComercialPorPais e BalancoComercialPorContinente. Estas estruturas serão utilizadas para a transmissão de objetos no formato JSON, a partir dos serviços detalhados mais adiante nesta seção.
O tipo BalancoComercialPorPais representa o resumo de exportações e importações para um país num determinado ano. Já instâncias de BalancoComercialPorContinente conterão informações comerciais relativas a um continente específico.
Listagem 1. Classes BalancoComercialPorPais e BalancoComercialPorContinente
using System;
namespace TesteWebAPI.Services.Models
{
public class BalancoComercialPorPais
{
public int AnoBase { get; set; }
public string Pais { get; set; }
public string Sigla { get; set; }
public double ValorExportado { get; set; }
public double ValorImportado { get; set; }
}
public class BalancoComercialPorContinente
{
public int AnoBase { get; set; }
public string Continente { get; set; }
public double ValorExportado { get; set; }
public double ValorImportado { get; set; }
}
}
Devido ao fato do projeto se prestar apenas à realização de testes, esta aplicação não fará uso de uma base de dados relacional. Por esse motivo, serão implementadas duas classes estáticas com o objetivo de retornar valores fictícios (SimulacaoBalanco2012 e SimulacaoBalanco2013), com cada uma destas estruturas possuindo resultados de um ano específico.
Na Listagem 2 está a definição da classe SimulacaoBalanco2012. A operação ObterBalancoPaises será utilizada para se ter acesso ao balanço comercial de diferentes países, ao passo que o método ObterBalancoContinentes retorna o mesmo tipo de informação agrupando os dados por continentes.
Listagem 2. Classe SimulacaoBalanco2012
using System;
using System.Collections.Generic;
namespace TesteWebAPI.Services.Models
{
public static class SimulacaoBalanco2012
{
public static List<BalancoComercialPorPais> ObterBalancoPaises()
{
List<BalancoComercialPorPais> dados =
new List<BalancoComercialPorPais>();
dados.Add(new BalancoComercialPorPais()
{
AnoBase = 2012,
Pais = "Alemanha",
Sigla = "DE",
ValorExportado = 38.6,
ValorImportado = 20.2
});
dados.Add(new BalancoComercialPorPais()
{
AnoBase = 2012,
Pais = "Canadá",
Sigla = "CA",
ValorExportado = 17.2,
ValorImportado = 3.4
});
dados.Add(new BalancoComercialPorPais()
{
AnoBase = 2012,
Pais = "China",
Sigla = "CN",
ValorExportado = 49.8,
ValorImportado = 36.2
});
dados.Add(new BalancoComercialPorPais()
{
AnoBase = 2012,
Pais = "Estados Unidos",
Sigla = "US",
ValorExportado = 55.4,
ValorImportado = 27.8
});
dados.Add(new BalancoComercialPorPais()
{
AnoBase = 2012,
Pais = "Japão",
Sigla = "JP",
ValorExportado = 44.2,
ValorImportado = 18.4
});
dados.Add(new BalancoComercialPorPais()
{
AnoBase = 2012,
Pais = "Reino Unido",
Sigla = "GB",
ValorExportado = 34,
ValorImportado = 7.8
});
return dados;
}
public static List<BalancoComercialPorContinente> ObterBalancoContinentes()
{
List<BalancoComercialPorContinente> dados =
new List<BalancoComercialPorContinente>();
dados.Add(new BalancoComercialPorContinente()
{
AnoBase = 2012,
Continente = "América",
ValorExportado = 72.6,
ValorImportado = 31.2
});
dados.Add(new BalancoComercialPorContinente()
{
AnoBase = 2012,
Continente = "Ásia",
ValorExportado = 94,
ValorImportado = 54.6
});
dados.Add(new BalancoComercialPorContinente()
{
AnoBase = 2012,
Continente = "Europa",
ValorExportado = 72.6,
ValorImportado = 28
});
return dados;
}
}
}
Já na Listagem 3 está o código que implementa o tipo SimulacaoBalanco2013. Conforme se observa, a estrutura aqui descrita é idêntica à da classe SimulacaoBalanco2012, diferindo apenas pelo conteúdo das informações retornadas.
Listagem 3. Classe SimulacaoBalanco2013
using System;
using System.Collections.Generic;
namespace TesteWebAPI.Services.Models
{
public static class SimulacaoBalanco2013
{
public static List<BalancoComercialPorPais> ObterBalancoPaises()
{
List<BalancoComercialPorPais> dados =
new List<BalancoComercialPorPais>();
dados.Add(new BalancoComercialPorPais()
{
AnoBase = 2013,
Pais = "Alemanha",
Sigla = "DE",
ValorExportado = 39.1,
ValorImportado = 20.9
});
dados.Add(new BalancoComercialPorPais()
{
AnoBase = 2013,
Pais = "Canadá",
Sigla = "CA",
ValorExportado = 17.8,
ValorImportado = 4
});
dados.Add(new BalancoComercialPorPais()
{
AnoBase = 2013,
Pais = "China",
Sigla = "CN",
ValorExportado = 50.5,
ValorImportado = 36.7
});
dados.Add(new BalancoComercialPorPais()
{
AnoBase = 2013,
Pais = "Estados Unidos",
Sigla = "US",
ValorExportado = 56.2,
ValorImportado = 28.2
});
dados.Add(new BalancoComercialPorPais()
{
AnoBase = 2013,
Pais = "Japão",
Sigla = "JP",
ValorExportado = 45.1,
ValorImportado = 18.7
});
dados.Add(new BalancoComercialPorPais()
{
AnoBase = 2013,
Pais = "Reino Unido",
Sigla = "GB",
ValorExportado = 35,
ValorImportado = 8
});
return dados;
}
public static List<BalancoComercialPorContinente> ObterBalancoContinentes()
{
List<BalancoComercialPorContinente> dados =
new List<BalancoComercialPorContinente>();
dados.Add(new BalancoComercialPorContinente()
{
AnoBase = 2013,
Continente = "América",
ValorExportado = 74,
ValorImportado = 32.2
});
dados.Add(new BalancoComercialPorContinente()
{
AnoBase = 2013,
Continente = "Ásia",
ValorExportado = 95.6,
ValorImportado = 55.4
});
dados.Add(new BalancoComercialPorContinente()
{
AnoBase = 2013,
Continente = "Europa",
ValorExportado = 74.1,
ValorImportado = 28.9
});
return dados;
}
}
}
Ao se gerar uma aplicação com o template “Web API” no Visual Studio, dois Controllers serão criados automaticamente (Figura 3):
- HomeController: estrutura que permite a visualização via browser de informações descrevendo as características da aplicação. Na página associada à View Index deste Controller existirá normalmente um link, que ao ser acessado exibirá uma listagem com os diferentes serviços (e respectivas operações) do projeto em questão;
- ValuesController: Controller que representa um exemplo de serviço Web API. O arquivo que contém a definição desta estrutura deverá ser removido da solução, já que novos Controllers serão implementados conforme descrito mais adiante.
OBSERVAÇÃO: Por questões de simplificação, foi omitido deste artigo o código referente ao Controller HomeController e às Views da aplicação TesteWebAPI.Services. A justificativa para isso está no fato de que não constam em tais estruturas instruções complexas, as quais justifiquem uma discussão mais aprofundada. Os arquivos correspondentes a essas construções podem ser obtidos através do download da solução aqui implementada, a partir da opção código fonte existente na própria página deste post.
Figura 3. Controllers gerados automaticamente ao se criar um novo projeto baseado no template Web API
Dois novos Controllers serão implementados no projeto TesteWebAPI.Services:
- PaisesController: estrutura responsável por retornar o balanço dos diferentes países com os quais a companhia mantém relações comerciais;
- ContinentesController: a função deste Controller será devolver como resultado o balanço comercial por continente.
O Controller PaisesController pode ser criado por meio da janela Solution Explorer: para isto, clicar com o botão direito do mouse sobre a pasta “Controllers”, selecionando em seguida no menu de atalho o item “Add”, opção “Controller...”. Aparecerá então a janela “Add Scaffold” (Figura 4); selecionar o template “Web API 2 - Controller Empty”. Já em “Add Controller” (Figura 5), definir “PaisesController” como nome do novo Controller.
Figura 4. Selecionando o template para criação de um novo Controller
Figura 5. Criando o Controller PaisesController
Na Listagem 4 está o código que define o Controller PaisesController. Analisando como essa estrutura foi implementada, é possível observar:
- A classe PaisesController deriva do tipo ApiController (namespace System.Web.Http). Todos os serviços desenvolvidos em Web API devem, obrigatoriamente, herdar da clássica básica ApiController. Este último tipo se encarrega do tratamento de requisições enviadas a um Web Service, com a posterior transmissão de uma resposta às aplicações-cliente;
- O método público Get foi criado com o intuito de processar qualquer requisição HTTP do tipo GET enviada ao Controller PaisesController. Esta operação recebe como parâmetro um ano-base e, caso este valor seja válido, devolve como resultado uma coleção de instâncias do tipo BalancoComercialPorPais (utilizando para isto os tipos SimulacaoBalanco2012 e SimulacaoBalanco2013). Importante destacar que o retorno do método Get é automaticamente convertido para o formato JSON, graças à forma como o tipo ApiController foi implementado dentro do framework ASP.NET Web API.
OBSERVAÇÃO: Por default, métodos declarados em um Controller como públicos e cujos nomes se iniciem por “Get”, “Post”, “Put” e “Delete” são mapeados automaticamente para o processamento das requisições HTTP correspondentes (GET, POST, PUT e DELETE, respectivamente).
Listagem 4. Controller PaisesController
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using TesteWebAPI.Services.Models;
namespace TesteWebAPI.Services.Controllers
{
public class PaisesController : ApiController
{
public IEnumerable<BalancoComercialPorPais> Get(int ano)
{
if (ano == 2012)
return SimulacaoBalanco2012.ObterBalancoPaises();
else if (ano == 2013)
return SimulacaoBalanco2013.ObterBalancoPaises();
else
throw new ArgumentException(
"O ano-base informado é inválido.");
}
}
}
O Controller ContinentesController deverá ser criado seguindo os mesmos passos descritos para PaisesController.
Na Listagem 5 está a implementação da classe ContinentesController. Essa estrutura foi definida de uma maneira bastante semelhante àquela do tipo PaisesController, herdando de ApiController e disponibilizando um método Get que retorna uma coleção de instâncias da classe BalancoComercialPorContinente (empregando mais uma vez as classes SimulacaoBalanco2012 e SimulacaoBalanco2013, a partir de um ano informado como parâmetro em uma solicitação HTTP).
Listagem 5. Controller ContinentesController
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using TesteWebAPI.Services.Models;
namespace TesteWebAPI.Services.Controllers
{
public class ContinentesController : ApiController
{
public IEnumerable<BalancoComercialPorContinente> Get(int ano)
{
if (ano == 2012)
return SimulacaoBalanco2012.ObterBalancoContinentes();
else if (ano == 2013)
return SimulacaoBalanco2013.ObterBalancoContinentes();
else
throw new ArgumentException("O ano-base informado é inválido.");
}
}
}
Executando o projeto TesteWebAPI.Services através do Visual Studio será exibida a tela apresentada na Figura 6. Além de toda a estrutura necessária à implementação de serviços RESTful, o template utilizado para a criação desta aplicação também gera um site MVC para a documentação dos Web Services implementados.
Figura 6. Executando o projeto TesteWebAPI.Services a partir do Visual Studio
Acessando o link “API” no cabeçalho da página, aparecerá então uma relação (Figura 7) dos diferentes serviços implementados na aplicação TesteWebAPI.Services. Foram detalhadas inclusive as operações existentes, bem como as URLs de acesso a cada uma destas Actions.
Figura 7. Serviços implementados na aplicação TesteWebAPI.Services
Acionando na página a documentação de uma das URL geradas (clicando sobre o link da mesma), serão exibidos detalhes da Action como parâmetros esperados, bem como o retorno produzido por estas operações nos formatos JSON e XML (Figura 8).
Figura 8. Detalhes da Action que retorna informações sobre países
Por empregar uma estrutura mais simples quando comparada a construções em XML, o formato JSON contribui para a transferência de menores volumes de dados entre Web Services e aplicações-cliente. Este é justamente um dos principais motivos que tornam JSON a alternativa mais popular em cenários que envolvam a arquitetura REST.
Conforme foi possível observar, as URLs dos serviços que compõem a aplicação contam com o seguinte padrão: iniciando com o endereço do site em que o projeto será hospedado e a palavra “api”, a URI para acesso a uma operação de um Web Service será formada ainda pelo nome do Controller (antecedido por uma barra), além de uma query string com os parâmetros previstos para cada Action (em ambos os casos possíveis deverá ser informado o ano).
Nota-se, portanto, que as URLs geradas até o momento não seguem o formato esperado descrito no ínicio desta seção (endereço do site + "/balanco/{controller}/{ano}"). Para que isto aconteça, será necessário alterar a classe WebApiConfig, como indicado na Listagem 7:
- O método Register é invocado durante a inicialização da aplicação, de forma a proceder com o registro das diferentes rotas/URLs para acesso às funcionalidades dos serviços disponíveis;
- A chamada ao método MapHttpAttributeRoutes (a partir do objeto “config”), será responsável por registrar rotas que foram configuradas sob a forma de atributos, os quais podem ter sido vinculados a Actions nos diferentes Controllers de uma aplicação;
- O acesso à propriedade Routes do objeto “config”, com a consequente invocação do método MapHttpRoute, possibilita a configuração de uma rota personalizada através do preenchimento do parâmetro “routeTemplate” (esta é na prática a única alteração realizada na classe WebApiConfig).
OBSERVAÇÃO: A implementação do tipo WebApiConfig está em um arquivo chamado WebApiConfig.cs, o qual por sua vez se encontra dentro da pasta App_Start do projeto TesteWebAPI.Services.
Listagem 7. Classe WebApiConfig
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
namespace TesteWebAPI.Services
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "balanco/{controller}/{ano}");
}
}
}
Após as mudanças em WebApiConfig, será necessário executar novamente a aplicação TesteWebAPI.Services. A página que descreve as APIs do projeto mostrará então que as URLs dos serviços estão em conformidade com o padrão esperado para as mesmas (Figura 9).
Figura 9. URLs modificadas para acesso aos serviços do projeto TesteWebAPI.Services
Com o Internet Explorer ativo, um teste simples poderá ser feito acessando a URL descrita a seguir: http://localhost:60913/balanco/paises/2013
strong>OBSERVAÇÃO: O valor “60913” corresponde a uma porta disponível no momento em que o projeto TesteWebAPI.Services foi implementado, sendo que tal número pode variar de um computador para outro.
Importante destacar que a URL mencionada está em conformidade com a arquitetura REST, já que representa um endereço único para acesso ao balanço comercial por países no ano de 2013. Na Figura 10 está o resultado dessa ação, em que o retorno obtido será uma string no formato JSON com os totais de importação e exportação para cada país. Já na Listagem 8 constam os dados por país referentes ao período citado.
Figura 10. Consumindo um dos serviços criados via Internet Explorer
Listagem 8. Balanço commercial por países no format JSON
[
{
"AnoBase":2013,
"Pais":"Alemanha",
"Sigla":"DE",
"ValorExportado":39.1,
"ValorImportado":20.9
},
{
"AnoBase":2013,
"Pais":"Canadá",
"Sigla":"CA",
"ValorExportado":17.8,
"ValorImportado":4.0
},
{
"AnoBase":2013,
"Pais":"China",
"Sigla":"CN",
"ValorExportado":50.5,
"ValorImportado":36.7
},
{
"AnoBase":2013,
"Pais":"Estados Unidos",
"Sigla":"US",
"ValorExportado":56.2,
"ValorImportado":28.2
},
{
"AnoBase":2013,
"Pais":"Japão",
"Sigla":"JP",
"ValorExportado":45.1,
"ValorImportado":18.7
},
{
"AnoBase":2013,
"Pais":"Reino Unido",
"Sigla":"GB",
"ValorExportado":35.0,
"ValorImportado":8.0
}
]
Este mesmo teste pode ser repetido a partir do Google Chrome. É o que demonstra a Figura 11, na qual o retorno produzido pelo Controller PaisesController foi um documento XML com os dados de países para o ano de 2013.
Figura 11. Consumindo um dos serviços criados via Google Chrome
Por fim, é útil destacar ainda que testes em serviços RESTful também podem ser realizados por meio do utilitário conhecido como Fiddler (conforme a Figura 12). Esta ferramenta é gratuita, dispondo de recursos que facilitam o teste de Web Services, análises envolvendo o tráfego de informações via protocolo HTTP/HTTPS, dentre outras funcionalidades englobando o monitoramento de aplicações Web.
Figura 12. Teste de um dos serviços criados via Fiddler
Conforme demonstrado ao longo deste artigo, a implementação de serviços Web API apresenta muitas similaridades quando comparada ao desenvolvimento de sites em ASP.NET MVC.
Empregando construções como Controllers e Actions, o framework Web API procura oferecer uma alternativa simples, rápida e flexível para a criação de Web Services baseados na arquitetura REST. A utilização de formatos como JSON e XML garante ainda um grau mínimo de interoperabilidade de tais serviços, algo que viabiliza o reuso destes componentes em aplicações concebidas nas mais variadas plataformas (como Java, PHP, Delphi, dentre outras).
Espero que o conteúdo aqui apresentado possa ser útil no seu dia a dia. Até uma próxima oportunidade!
Links
ASP.NET Web API: http://www.asp.net/web-api
Fiddler free web debugging proxy: http://www.telerik.com/fiddler