Você está na página 1de 85

Tpicos relacionados ao

desenvolvimento de APIs Web


utilizando a plataforma Microsoft
ASP.NET.

ASP.NET
Web API
Introduo

Israel Aece
http://www.israelaece.com
Contedo
Prefcio ............................................................................................................................. 3

Introduo ........................................................................................................................ 5

HTTP, REST e o ASP.NET ................................................................................................... 7

Estrutura da API .............................................................................................................. 12

Roteamento .................................................................................................................... 32

Hosting ............................................................................................................................ 42

Consumo ......................................................................................................................... 46

Formatadores ................................................................................................................. 53

Segurana ....................................................................................................................... 60

Testes e Tracing .............................................................................................................. 67

Arquitetura e Estensibilidade ......................................................................................... 77

2
Prefcio
A multiplicao de dispositivos representa um desafio e uma oportunidade para os
desenvolvedores de software. Nossos sistemas so executados em computadores,
telefones, tablets, aparelhos de TV. As possibilidades so muitas e as dificuldades so
ainda maiores. Arquiteturas convencionais de software no atendem mais, de forma
satisfatria, essa pluralidade de plataformas, tanto de hardware quanto operacionais,
com que temos de lidar. H bem pouco tempo, falava-se em sistemas Web como uma
alternativa para reduzir os obstculos de distribuio. Hoje, esse argumento parece no
ser mais suficiente.

Nesse mesmo cenrio, temos empresas que operam dezenas algumas falam em
centenas ou, at mesmo, milhares de sistemas. Tudo isso com "algum nvel" de
integrao. Entretanto, a competitividade tem exigido dessas empresas e, em
consequncia, de seus sistemas, grande flexibilidade e agilidade. Regras de negcio so
includas, revisadas e modificadas frequentemente. Aquisies e fuses trazem ainda
mais sistemas com sobreposies aos existentes, inclusive que tambm precisam ser
mantidos e integrados.

Tanto a pluralidade de plataformas, como a flexibilidade e multiplicidade inevitvel de


sistemas, tem levado ao desenvolvimento de arquiteturas que separam, de forma
consistente, as interfaces com usurio da exposio efetiva das funcionalidades das
aplicaes. De fato, crescente a adoo de arquiteturas orientadas a servio (SaaS).
Ou seja, cada vez mais o "core" das aplicaes pode ser acessado remotamente atravs
de interfaces programveis (APIs) permitindo, dessa forma, o desenvolvimento de
aplicaes leves e ajustadas para diversas plataformas, bem como a adoo de prticas
efetivas de integrao.

Arquiteturas baseadas em servios tambm so comuns em desenvolvimento de


aplicaes B2C. Empresas como Facebook, Twitter, Google e Microsoft j as adotam h
muito tempo. Hoje, podemos escrever facilmente aplicaes que consomem e se
integram a essas plataformas graas a essa caracterstica.

Sensvel a necessidade crescente de arquiteturas orientadas a servio, vimos o


surgimento de diversos frameworks. Dentre eles, est o Microsoft ASP.net Web API.
Trata-se de uma tecnologia leve para o desenvolvimento de servios baseados em HTTP,
desenvolvida pela Microsoft, que destaca-se pela elegncia, objetividade e simplicidade.
Com ASP.net Web API, podemos desenvolver servios HTTP plenamente adaptados ao
modelo REST, com suporte a diversas formataes (XML e JSON so suportados
nativamente), que so fceis de testar, consumir e manter. Alm de tudo isso, h ainda
um amplo suporte de ferramentas de desenvolvimento, distribuio, hospedagem e
manuteno - providas pela prpria Microsoft ou terceiros.

Este livro uma introduo sria ao desenvolvimento de servios usando Microsoft


ASP.net Web API. Ele foi escrito por uma das maiores autoridades nesse assunto e um
dos profissionais de TI mais respeitados no Brasil. H muitos anos, Israel Aece vem
compartilhando conhecimentos com a comunidade desenvolvedora. Alm disso, ele

3
tem ensinado, inspirado e influenciado a forma como eu penso o desenvolvimento de
servios Web. Por isso, sinto-me imensamente honrado pela oportunidade de
recomendar esse livro. Aqui, voc encontrar uma orientao valiosa para adoo e uso
de Web API. uma leitura agradvel mesmo para desenvolvedores que j dominem o
framework. Alis, um daqueles livros que gostaria de ter tido a oportunidade de ler h
mais tempo.

Elemar Junior
http://elemarjr.net

4
Introduo
Com a popularizao da internet temos cada vez mais informaes sendo
disponibilizadas em tempo real, acessos recursos que antes eram apenas possveis em
algum ponto especfico e com uma srie de limitaes. A evoluo tornou o acesso a
estas informaes muito mais dinmica, conseguindo acess-la a qualquer momento,
em qualquer lugar e, principalmente, em qualquer dispositivo.

Com isso em mente algumas opes foram sendo criadas para permitir com que as
aplicaes pudessem disponibilizar tais informaes e outras pudessem consumir. Mas
em pouco tempo foram criadas diversas tecnologias e padres para isso, e opes que
tnhamos at pouco tempo atrs, hoje j so obsoletas.

A proposta deste livro introduzir a tecnologia que a Microsoft incorporou no ASP.NET


para a construo e o consumo de APIs Web. A ideia formar o conhecimento desde a
introduo estrutura, passando pela arquitetura e alguns detalhes internos sobre o
funcionamento, que permitir extrair grande parte do potencial que esta tecnologia
fornece.

Como pr-requisitos deste livro, precisaremos de conhecimento em alguma linguagem


.NET (os exemplos sero baseados em C#) e, opcionalmente, alguma familiaridade com
projetos Web no Visual Studio, para conseguirmos utilizar a IDE a nosso favor em alguns
pontos importantes durante o desenvolvimento.

Captulo 1 HTTP, REST e o ASP.NET: Para basear todas as funcionalidades expostas


pela tecnologia, precisamos ter um conhecimento bsico em relao ao que motivou
tudo isso, contando um pouco da histria e evoluo, passando pela estrutura do
protocolo HTTP e a relao que tudo isso tem com o ASP.NET.

Captulo 2 Estrutura da API: Entenderemos aqui a template de projeto que o Visual


Studio fornece para a construo das APIs, bem como sua estrutura e como ela se
relaciona ao protocolo.

Captulo 3 Roteamento: Como o prprio nome diz, o captulo ir abordar a


configurao necessria para que a requisio seja direcionada corretamente para o
destino solicitado, preenchendo e validando os parmetros que so por ele solicitado.

Captulo 4 Hosting: Um captulo de extrema relevncia para a API. o hosting que d


vida API, disponibilizando para o consumo por parte dos clientes, e a sua escolha
interfere diretamente em escalabilidade, distribuio e gerenciamento. Existem
diversas formas de se expor as APIs, e aqui vamos abordar as principais delas.

Captulo 5 Consumo: Como a proposta ter uma API sendo consumido por qualquer
cliente, podem haver os mais diversos meios (bibliotecas) de consumir estas APIs. Este
captulo tem a finalidade de exibir algumas opes que temos para este consumo,
incluindo as opes que a Microsoft criou para que seja possvel efetuar o consumo por
aplicaes .NET.

5
Captulo 6 Formatadores: Os formatadores desempenham um papel importante na
API. So eles os responsveis por avaliar a requisio, extrair o seu contedo, e quando
a resposta devolvida ao cliente, ele entra em ao novamente para formatar o
contedo no formato em que o cliente possa entender. Aqui vamos explorar os
formatadores padres que j esto embuitdos, bem como a criao de um novo.

Captulo 7 Segurana: Como a grande maioria das aplicaes, temos tambm que nos
preocupar com a segurana das APIs. E quando falamos de aplicaes distribudas, alm
da autenticao e autorizao, necessrio nos preocuparmos com a segurana das
mensagens que so trocadas entre o cliente e o servio. Este captulo ir abordar
algumas opes que temos disponveis para tornar as APIs mais seguras.

Captulo 8 Testes e Tracing: Para toda e qualquer aplicao, temos a necessidade de


escrever testes para garantir que a mesma se comporte conforme o esperado. Isso no
diferentes com APIs Web. Aqui iremos abordar os recursos, incluindo a prpria IDE,
para a escrita, gerenciamento e execuo dos testes.

Captulo 9 Estensibilidade e Arquitetura: Mesmo que j tenhamos tudo o que


precisamos para criar e consumir uma API no ASP.NET Web API, a customizao de
algum ponto sempre acaba sendo necessria, pois podemos criar mecanismos
reutilizveis, externalizando-os do processo de negcio em si. O ASP.NET Web API foi
concebido com a estensibilidade em mente, e justamente por isso que existe um
captulo exclusivo para abordar esse assunto.

Por fim, este livro foi escrito com utilizando o Visual Studio 2012 com Update 3, ASP.NET
and Web Tools 2012.2, .NET Framework 4.5 e Visual Studio Express 2013 Preview for
Web para criar e executar os exemplos contidos aqui. Qualquer dvida, crtica ou
sugesto, entre em contato atravs do site http://www.israelaece.com ou enviando um
e-mail para ia@israelaece.com.

6
HTTP, REST e o ASP.NET
Os sistemas que so construdos atualmente produzem toneladas e toneladas de
informaes, que so armazenadas em uma base de dados, para mais tarde, estas
mesmas informaes sero consumidas por estas e outras aplicaes.

No existe muitos problemas enquanto h apenas uma nica aplicao consumidora


destas informaes, afinal ela pode consumir diretamente a base de dados para ler e
gravar as informaes desejadas. Se estamos dentro de um ambiente controlado, como
por exemplo, aplicaes construdas dentro de uma mesma empresa, podemos utilizar
a prpria base de dados para integrar as mesmas.

Enquanto estamos consumindo informaes locais, estamos diretamente conectados a


nossa infraestrutura, sem qualquer impeclio mais crtico para acessar e consumir as
informaes. O dinamismo do mercado faz com que hoje as empresas operem em
tempo real, onde as informaes que precisam ser consumidas ou disponibilizadas esto
alm do ambiente interno, ou seja, a necessidade de uma integrao real com parceiros
de negcios, rgos governamentais, etc.

Utilizar a base de dados como meio de integrao no mais uma opo. Estamos agora
lidando com empresas que esto fora da nossa rede, com aplicaes construdas com
tecnologias diferentes daquelas que adotamos internamente, padres diferentes, etc.

Tudo isso motivou algumas grandes empresas de tecnologia do mundo a trabalharem


na construo de forma de integrao, criando um padro predefinido para troca de
informaes entre tais empresas. Em pouco tempo surgiu o conceito de Web Services,
onde a ideia permitir com que sistemas se conectem a fim de trocar informaes entre
eles, sem a necessidade da interveno humana.

Para dar suporte a tudo isso, o XML foi utilizado como forma de expressar essa
comunicao entre as partes. O XML uma linguagem de marcao, e que apesar de ser
texto puro, fornece uma gama de outros recursos agregados que o torna bastante
poderoso, como por exemplo, a possibilidade de estensvel, separar definio de
contedo, opes para validao de estrutura, simplicidade na leitura (inclusive por
humanos).

Como a internet estava cada vez mais difundida, utiliz-la como forma de integrao foi
uma das principais opes, pois tratavam-se de tecnologias de padro aberto, como o
caso do HTTP e HTML. O HTTP d vida aos Web Services, pois ele que o torna acessvel,
para que as aplicaes interessadas possam acess-los e trocar as informaes. Alm
disso, o fato de se apoiar em tecnologias de padro aberto, torna o consumo muito mais
simplificado pelas mais diversas linguagens e tecnologias, desde uma aplicao de linha
de comando, passando por um navegador e at mesmo um dispositivo mvel.

Sendo o HTTP o responsvel pela infraestrutura de comunicao e o XML a linguagem


que descrever a comunicao, ainda era necessrio um formato para formalizar a
interao entre as partes (produtora e consumidora). Eis que surge o SOAP (Simple

7
Object Access Protocol). A finalidade do SOAP foi padronizar o contedo que trafega
entre as partes sob o protoloco HTTP. O SOAP baseado em XML e, consequentemente,
estensvel, e em pouco tempo ele ficou popular e foi utilizado em larga escala. Cada
empresa utilizou as especificaes criadas e regidas por rgos independentes, criando
um ferramental para que seja possvel a criao e consumo destes tipos de servios. A
Microsoft fez a sua parte criando os ASP.NET Web Services (ASMX), que seguia as
especificaes do W3C para a criao e consumo de servios dentro da plataforma .NET,
e isso contribuiu ainda mais para a popularizao destes tipos de servios.

O grande uso destes tipos de servios motivou a criao de algumas outras tecnologias
para incrementar os Web Services, incluindo algumas caractersticas referentes a
segurana, entrega de mensagens, transaes, etc., e ento uma srie de especificaes
(WS-*) foram criadas (graas a estensibilidade que o SOAP possibilita), a fim de
padronizar cada um destes novos recursos. A Microsoft correu para adequar os ASP.NET
Web Services para suportar estas novas funcionalidades, e a surgiu o WS-E (Web
Services Enhancements).

Dentro do universo Microsoft h vrias opes para comunicao distruda, onde cada
uma tinha um objetivo diferente, uma implementao nica e uma API nada comum.
Com o intuito de facilitar a comunicao distribuda dentro da plataforma .NET ela
construiu o WCF Windows Communication Foundation. Ele um dos pilares do .NET
Framework, sendo o framework de comunicao para toda a plafaforma. O WCF unifica
todas as tecnologias de comunicao distribudas que a Microsoft tinha at ento. A
proposta com ele tornar a construo e consumo de servios algo simples, onde o foco
est apenas nas regras de negcios, e detalhes com a infraestrutura, comunicao,
protocolo, etc., seriam poucas configuraes a serem realizadas.

O WCF foi construdo com o protocolo (HTTP, TCP, MQ) sendo apenas uma forma de
comunicao, onde o SOAP o padro que define todo o trfego das mensagens,
independentemente do protocolo que seja utilizado para a comunicao.

Como vimos at ento, o SOAP se apresenta como a soluo ideal para a integrao
entre os mais variados sistemas, de qualquer tecnologia, justamente por trabalhar com
padres abertos e gerenciados por rgos independentes. S que o SOAP foi ganhando
uma dimenso em funcionalidades, e grande parte das plataformas e linguagens no
conseguiram acompanhar a sua evoluo, tornando cada vez mais complicado a sua
adoo, pois a cada nova funcionalidade adicionada, uma srie de novos recursos
precisam serm, tambm, adicionados nas plataformas/linguagens para suportar isso.

Motivada pela complexidade que o SOAP ganhou ao longo do tempo, e tambm pela
dificuldade na evoluo por parte dos produtos e consumidores destes tipos de servios,
uma nova alternativa foi ganhando cada vez mais espao: o REST (Representational State
Transfer). O estilo REST vai contra tudo o que prega o SOAP, ou seja, enquanto o SOAP
entende que o HTTP uma forma de trfego da informao, o REST abraa o HTTP,
utilizando integralmente todos os seus recursos.

8
Orientado recursos, o estilo REST define o acesso elementos como se eles fossem
um conjunto predefinido de informaes quais queremos interagir (acessvel atravs de
sua URI), extraindo e/ou criando estes recursos, diferindo do estilo baseado em RPC
(Remote Procedure Call) que usvamos at ento, que define que o acesso alguma
funcionalidade.

Novamente, correndo atrs do que o mercado estava utilizando como principal meio de
comunicao e integrao, a Microsoft comeou a trabalhar em uma nova verso do
WCF, j que era o pilar de comunicao da plataforma, para agregar a possibilidade de
construir servios baseados em REST. Passamos ento a ter a possibilidade de criar este
tipo de servio no WCF, mas como o mesmo foi construdo abstraindo a figura do
protocolo (HTTP e outros), ficou complexo demais criar servios REST sobre ele, j que
era necessrio entender toda a infraestrutura do WCF para criar um servio deste tipo,
pois para interagir com os elementos do HTTP, tnhamos que lidar com objetos do
framework que passava a expor o acesso aos recursos do HTTP (URIs, headers,
requisio, resposta, etc.).

Como a criao de servios REST no WCF acabou ficando mais complexo do que deveria,
a Microsoft comeou a investir na criao de uma nova forma de construir e consumir
servios REST na plataforma .NET. Inicialmente ele seria uma espcie de agregado ao
WCF, mas pela complexidade de manter o modelo de classes que j existia, a Microsoft
decidiu criar a vincular isso ao ASP.NET, tornando-o uma plataforma completa para a
criao de qualquer funcionalidade para ser exposta via Web, e assim surgiu o ASP.NET
Web API. Como toda e qualquer tecnologia, o ASP.NET Web API abstrai vrios elementos
que so necessrios para o funcionamento destes tipos de servios. Mas isso no
motivo para no entender quais so e para o que eles servem.

Web API nada mais que uma interface que um sistema expe atravs do HTTP para ser
acessado pelos mais variados clientes, utilizando as caractersticas do prprio protocolo
para interagir com o mesmo. E como estamos agora fundamentados no HTTP,
necessrio conhecermos alguns elementos que passam a ser essencias para a
construo destes servios. Sendo assim, quando estamos lidando com a Web, toda e
qualquer requisio e resposta possuem algumas caractersticas especficas que
envolvem todo o processo, a saber:

Recursos: recursos podem ser qualquer coisa que esteja disponvel e desejamos
acessar. Podemos entender o recurso como uma pgina HTML, produtos de uma
loja, um video, uma imagem e tambm uma funcionalidade que pode ser
acessvel atravs de outras aplicaes.
URIs: Todo e qualquer recurso para ser acessvel, precisa ter uma URI que
determina o endereo onde ele est localizado. A URI segue a seguinte estrutura:
http://Servidor/MusicStore/Artistas?max+pezzali.
Representao: Basicamete uma fotografia de um recurso em um
determinado momento.
Media Type: O recurso retornado ao cliente uma fotografia em um
determinado momento, seguindo um determinado formato. O Media Type

9
responsvel por determinado o formato em que a requisio enviado e como
a resposta devolvida. Alguns media types: image/png, text/plain, etc.

Se depurarmos uma requisio para qualquer tipo de API via HTTP, podemos enxegar
cada um dos elementos elencados acima. Novamente, apesar de no ser necessrio
entender os bastidores da comunicao, o entendimento bsico nos dar
conhecimento para depurar e encontrar mais facilmente eventuais problemas,
entendimento para tirar proveito de alguns recursos que o prprio HTTP nos fornece.

O HTTP baseado no envio e recebimento de mensagens. Tanto a requisio quanto a


resposta HTTP possui a mesma estrutura. Temos o cabealho da mensagem, uma linha
em branco, e o corpo da mensagem. O cabealho composto por informaes inerentes
ao endereo do servio e um conjunto de headers, que nada mais que um dicionrio
contendo uma srie de informaes contextuais requisio/resposta, que guiar o
servio ou o cliente a como tratar a mensagem.

POST http://localhost:1062/api/clientes HTTP/1.1


User-Agent: Fiddler
Content-Type: application/json
Host: localhost:1062
Content-Length: 48

{"Nome": "Israel", "Email": "ia@israelaece.com"}

Na primeira linha vemos a forma (verbo) e para onde (URI) a requisio est sendo
encaminhada. Vale lembrar que o verbo tem um significado importante no HTTP, pois
ele determina o formato da mensagem e como ela ser processada. Vemos tambm o
Content-Type, que determina o formato do contedo da mensagem, e que neste caso,
est serializado em JSON. Depois da linha em branco temos o contedo da mensagem.
Se olharmos o todo, vemos que o cliente est interessado em postar (adicionar) um novo
cliente chamado Israel na coleo de clientes.

Depois de processado pelo cliente, e partindo do princpio que tudo deu certo, uma
mensagem de resposta ser retornada, e l teremos informaes referente ao
processamento da requisio (referente ao sucesso ou a falha):

HTTP/1.1 201 Created


Content-Type: application/json; charset=utf-8
Location: http://localhost:1062/api/clientes/12
Content-Length: 58

{"Id": 12, "Nome": "Israel", "Email": "ia@israelaece.com"}

Estruturalmente a mensagem de resposta igual a da requisio, com cabealho, linha


em branco e o corpo. A resposta contm tambm a coleo de headers, incluindo o
Content-Type do corpo, pois a entidade postada est sendo retornada ao cliente
informando, atravs do cdigo de status 201 (Created), que o cliente foi criado com
sucesso e o Id que foi gerado e atribudo ele.

10
Claro que o HTTP fornece muito mais do que isso que vimos nestes exemplos de
requisio e resposta. No decorrer dos prximos captulos iremos abordarmos com mais
detalhes cada um desses elementos e diversos outros recursos que sob demanda iremos
explorando e, consequentemente, agregando e exibindo novas funcionalidades que o
HTTP fornece.

11
Estrutura da API
Apesar de servios REST utilizar completamente o HTTP, importante que tenhamos
suporte para a construo e consumo destes tipos de servios. Precisamos entender
como estruturar, configurar e distribuir estes tipos de servios.

Para facilitar tudo isso, a Microsoft preparou o ASP.NET para suportar o


desenvolvimento de servios REST. A finalidade deste captulo introduzir a template
de projeto que temos, a API, a configurao mnima para a construo e exposio do
mesmo.

A Template de Projeto

A construo de Web API est debaixo de um projeto ASP.NET MVC 4, e logo na


sequncia da escolha deste projeto, voc deve escolher qual a template de projeto.
Neste caso, temos que recorrer a opo chamada Web API, conforme vemos nas
imagens abaixo. O projeto j est pr-configurado com o que precisamos para criar um
servio REST e expor para que seja consumido, sem a necessidade de realizar muitas
configuraes.

Figura 1 - Escolha da Template do Projeto

12
O projeto j est configurado com as referncias (DLLs) necessrias que contm os tipos
e membros que utilizaremos na construo das Web APIs, sendo a principal delas o
assembly System.Web.Http.dll. Dentro deste assembly temos vrios namespaces com
todos os elementos necessrios que iremos utilizar para a construo de Web APIs.
Alm disso, j temos algumas configuraes definidas para que seja possvel criar e
executar uma API criada, sem a necessidade de conhecer detalhes mais profundos em
um primeiro momento.

Analisando os itens do Solution Explorer, vemos que alm dos arquivos tradicionais de
um projeto ASP.NET (como o Global.asax e o Web.config), vemos ali um arquivo
chamado WebApiConfig.cs, que uma classe que contm a configurao padro do
roteamento (que ser abordado mais adiante) para o funcionamento dos servios REST.
Alm disso, temos um servio j criado como exemplo, que est contido na
classe/arquivo ValuesController.cs.

Figura 2 - Elementos Padro de um Projeto Web API

A classe ApiController

A construo de Web APIs utilizando o ASP.NET segue uma certa simetria em relao a
construo de um site baseado no padro MVC. Para a construo de views o MVC exige
que se tenha um controlador (controller) para receber, processar e retornar as
requisies que so realizadas para o site.

De forma parecida trabalha a Web API. Todas as Web APIs construdas no ASP.NET
devem herdar de uma classe abstrata chamada ApiController. Esta classe fornece toda
a infraestrutura necessria para o desenvolvimento destes tipos de servios, e entre as

13
suas tarefas, temos: fazer a escolha do mtodo a ser executado, converso das
mensagens em parmetros, aplicao de eventuais filtros (de vrios nveis), etc. Cada
requisio, por padro, ter como alvo um mtodo dentro desta classe, que ser
responsvel por processar a mesma e retornar o resultado.

A criao de uma Web API pode ser realizada de forma manual herdando da classe
ApiController, ou se preferir, pode ser utilizado o assistente que o prprio Visual Studio
disponibiliza, onde j existe algumas opes predefinidas para que a classe j seja criada
com a estrutura bsica para alguns cenrios.

Figura 3 -Opes para a criao do Controller

Independentemente da forma que voc utilize para a criao do controlador, sempre


teremos uma classe que servir como a base para a API, e o cdigo abaixo ilustra a
herana da classe ApiController:

using System.Web.Http;

namespace MusicStore.Controllers
{
public class ArtistasController : ApiController
{
}
}

Uma considerao importante com relao ao sufixo Controller que o nome da classe
que representar a API dever ter. Apesar dele ser transparente para o cliente, isso
utilizado pelo ASP.NET para encontrar o controller durante a requisio. Podemos notar
tambm que a classe no possui nenhum mtodo. Para que ela comece a ter sentido,

14
precisamos criar os mtodos que atendero as requisies que sero feitas para este
servio. Da mesma forma que fazemos no MVC, aqui criaremos as aes que retornaro
dados aos clientes, formatados em algum padro e, opcionalmente, os clientes podero
parametrizar a requisio, caso o servio permita isso.

A classe pode ter quantos mtodos forem necessrios, apenas temos que ter um pouco
do bom senso aqui para no darmos mais funcionalidade do que deveria para a mesma,
considerando a granularidade. A criao dos mtodos possuem algumas convenes
que se seguidas corretamente, no haver maiores configuraes a serem realizadas
para que ele j esteja acessvel ao rodar o servio.

Mas como que o ASP.NET escolhe qual dos mtodos acessar? O HTTP possui o que
chamamos de verbos (algumas vezes chamados de mtodos), e os mais comuns so:
GET, POST, PUT e DELETE, e cada um deles indica uma determinada ao a ser executada
em um recurso especfico.

GET: Est requisitando ao servio um determinado recurso, apenas isso. Este


verbo deve apenas extrair a informao, no alterando-a.
POST: Indica ao servio que a ele deve acatar o recurso que est sendo postado
para o mesmo, e que muito vezes, o adicionamos em algum repositrio.
PUT: Indica que ao servio que o recurso que est sendo colocado deve ser
alterado se ele j existir, ou ainda, pode ser adicionado caso ele ainda no exista.
DELETE: Indica que o servio deve excluir o recurso.

Mas o que isso tem a ver com o Web API? O ASP.NET j mapeia todos estes conhecidos
verbos do HTTP para mtodos que estejam criados o interior do controller. Para que isso
acontea, precisamos definir os mtodos com o nome de cada verbo acima descrito, e
com isso, automaticamente, quando o ASP.NET recepcionar a requisio, esse ser o
primeiro critrio de busca aos mtodos.

public class ArtistasController : ApiController


{
public Artista Get(int id)
{
}

public void Post(Artista novoArtista)


{
}
}

claro que no estamos condicionados a trabalhar desta forma. Se voc quer criar uma
API em portugus, talvez utilizar a configurao padro no seja a melhor opo pela
coerncia. Podemos nomear os mtodos da forma que desejarmos, mas isso nos
obrigar a realizar algumas configuraes extras, para direcionar o ASP.NET a como
encontrar o mtodo dentro da classe, pois agora, difere daquilo que foi previamente
configurado.

15
Para realizar essa configurao, vamos recorrer alguns atributos que j existem dentro
do ASP.NET e que foram construdos para cada um dos verbos do HTTP:
HttpGetAttribute, HttpPutAttribute, HttpPostAttribute, HttpDeleteAttribute, etc.
Quando um destes atributos colocado em um mtodo, ele permitir que ele seja
acessvel atravs daquele verbo. Utilizando o mesmo exemplo anterior, se alterarmos o
nome dos mtodos apenas, eles deixaro de estar acessveis aos clientes.

public class ArtistasController : ApiController


{
[HttpGet]
public Artista Recuperar(int id)
{
}

[HttpPost]
public void Adicionar(Artista novoArtista)
{
}
}

E ainda, como alternativa, podemos recorrer ao atributo ActionNameAttribute para


alterar o nome que ser publicado em relao aquele que definido no mtodo, dando a
chance de utilizar uma conveno de nomenclatura para escrita e outra para publicao.

public class ArtistasController : ApiController


{
[ActionName(Recuperar)]
public Artista Get(int id)
{
}
}

Como comentado acima, existe um atributo para cada verbo. Para uma maior
flexibilidade, temos tambm o atributo AcceptVerbsAttribute, que nos permite informar
em seu construtor quais os verbos que podem chegar at o mtodo em questo.

public class ArtistasController : ApiController


{
[AcceptVerbs("POST", "PUT")]
public void Adicionar(Artista novoArtista)
{
}
}

E se houver um mtodo pblico que se encaixe com as regras dos verbos que foram
comentadas acima e no queremos que ele esteja disponvel publicamente, podemos
proibir o acesso decorando o mtodo com o atributo NonActionAttribute.

Parametrizao dos Mtodos

Todos os mtodos podem receber informaes como parmetros, e como sada,


podemos retornar alguma informao que caracteriza o sucesso ou a falha referente a

16
execuo do mesmo. Quando falamos de mtodos que so disponibilizados para acesso
remoto, isso no diferente.

Os mtodos podem necessitar alguns parmetros para executar a tarefa que est sendo
solicitada. Os parmetros podem ter tipos mais simples (como inteiro, string, etc.) at
objetos mais complexos (Usuario, Pedido, Produto, etc.). A utilizao de objetos
complexo nos permite descrever o nosso negcio, tornando-o bem mais intuitivo que
criar um mtodo contendo uma infinidade de parmetros.

Figura 4 - Postando um recurso de um objeto complexo.

17
Apesar de estarmos habituados a declarar o mtodo, seus parmetros e resultado da
forma tradicional quando estamos construindo uma Web API, eles so trafegados entre
o cliente e o servio utilizando o modelo do HTTP, ou seja, eles podero ser carregados
atravs de querystrings, headers ou do corpo das mensagens.

De forma semelhante ao que ocorre no ASP.NET MVC, o ASP.NET Web API capaz de
mapear as querystrings (que so tipos simples (textos, nmeros, etc.)) para os
parmetros dos mtodos do controller de forma automtica. J os objetos complexos
viajam entre o cliente e o servio (e vice-versa) no corpo da mensagem. Toda a mgica
da transformao da mensagem em um objeto customizado realizada pelos
formatadores de contedo, qual ter um captulo especfico para abordar este assunto.

Quando estamos acessando os mtodos atravs do verbo GET, as querystrings so


mapeadas para os parmetros destes mtodos; j quando realizamos o POST, o corpo
da mensagem transformado no objeto complexo, conforme vimos na imagem acima.
Existe algumas opes mais rebuscadas se quisermos customizar como estes
parmetros so lidos das mensagens, e para isso, podemos recurrer aos atributos
FromBodyAttribute ou ao FromUriAttribute. Estes atributos nos permite direcionar o
ASP.NET a buscar os valores para abastecer os parmetros em locais diferentes dos
padres.

Podemos abastecer os parmetros baseados nas querystrings ou no corpo da


mensagem. O corpo da mensagem pode estar em diversos formatos (abordaremos com
mais detalhes adiante), e um deles a postagem sendo realizada atravs de um
formulrio HTML.

<form action="http://localhost:43139/api/Artistas/Adicionar" method="post">


<input type="text=" id="Id" name="Id" />
<input type="text=" id="Nome" name="Nome" />
<input type="text=" id="Email" name="Email" />
<input type="submit" name="Enviar" value="Enviar" />
</form>

Ao preencher os campos e postar o formulrio, podemos capturar a requisio e analisar


o que est sendo enviado ao servio mencionado. O que chama ateno na requisio
abaixo o header Content-Type definido como application/x-www-form-urlencoded,
que corresponde ao valor padro para formulrios HTML. No corpo da mensagem temos
os campos do formulrio separados pelo caracter &. J os espaos so substitudos pelo
caracter +. E, para finalizar, o nome do controle definido como chave, enquanto o
contedo do controle definido como valor no dicionrio.

POST http://localhost:43139/api/artistas/adicionar HTTP/1.1


User-Agent: Fiddler
Host: localhost:43139
Content-Type: application/x-www-form-urlencoded
Content-Length: 41

Id=12&Nome=Israel&Email=ia@israelaece.com

18
Ao postar um formulrio para um mtodo que possui um objeto, o ASP.NET Web API j
capaz de extrair as informaes do corpo da mensagem (a partir do dicionrio de
valores) e abastecer cada propriedade deste objeto. Se desejar, podemos ler
individualmente as informaes que esto sendo encaminhadas, no acionando o
formatador de contedo, utilizando um outro tipo de codificao quando estamos
postando o formulrio.

No exemplo acima, o formulrio foi postado utilizando o formato application/x-www-


form-urlencoded, que mais ou menos os valores do formulrio codificados como se
fossem itens de uma querystring. Existe um outro formato que o multipart/form-data,
que possui uma codificao mais sofisticada. Em geral, ele utilizado em conjunto com
o elemento do tipo file, que quando queremos fazer upload de arquivos para o
servidor.

Quando postamos um arquivo, automaticamente o tipo definido como sendo


multipart/form-data e na sequencia, vemos o arquivo anexado.

POST http://localhost:43139/api/artistas/AlterarFoto HTTP/1.1


Content-Type: multipart/form-data; boundary=-------------------------acebdf13572468
User-Agent: Fiddler
Host: localhost:43139
Content-Length: 1168

---------------------------acebdf13572468
Content-Disposition: form-data; name="fieldNameHere"; filename="MaxPezzali.png"
Content-Type: image/png

---- REMOVIDO POR QUESTES DE ESPAO ---

Mas para recepcionar este tipo de requisio temos que preparar o servio. Note que
ele no recebe nenhum parmetro; ele extrado do corpo da mensagem ao executar
o mtodo ReadAsMultipartAsync, que assincronamente l e materializa os arquivos,
salvando automaticamente no caminho informado no provider. Se desejar, podemos
iterar atravs da propriedade Contents, acessando individualmente cada um dos
arquivos que foram postados.

[HttpPost]
public async Task<HttpResponseMessage> AlterarFoto()
{
var provider =
new MultipartFormDataStreamProvider(
HttpContext.Current.Server.MapPath("~/Uploads"));

return await Request


.Content
.ReadAsMultipartAsync(provider)
.ContinueWith<HttpResponseMessage>(t =>
{
if (t.IsFaulted || t.IsCanceled)
return Request.CreateErrorResponse(
HttpStatusCode.InternalServerError, t.Exception);

return Request.CreateResponse(HttpStatusCode.OK);
});
}

19
Apesar das tcnicas acima serem interessantes, utilizar uma delas pode ser um
problema ao trabalhar com servios REST, devido ao fato de que em algumas situaes
haver a necessidade de ter o controle total das mensagens HTTP.

Com o intuito de facilitar e dar mais controle para ao desenvolvedor, a Microsoft inclui
nesta API classes que representam a mensagem de requisio (HttpRequestMessage) e
de resposta (HttpResponseMessage). Cada uma dessas classes trazem vrias
propriedades, onde cada uma delas expe caractersticas do protocolo HTTP, tais como:
Content, Headers, Method, Uri, StatusCode, etc.

O servio passar a utilizar essas classes em seus mtodos, ou seja, receber um


parmetro do tipo HttpRequestMessage, que possui todas as informaes necessrias
solicitadas pelo cliente, enquanto o retorno ser do tipo HttpResponseMessage, que
ser onde colocaremos todas as informaes de resposta para o mesmo cliente, sendo
essas informaes o resultado em si, o cdigo de status do HTTP, eventuais headers, etc.

public class ArtistasController : ApiController


{
[HttpGet]
public HttpResponseMessage Ping(HttpRequestMessage info)
{
return new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent("ping...")
};
}
}

O corpo da mensagem de retorno tambm pode ser customizado, onde podemos


retornar uma simples string ou at mesmo um objeto complexo. Isso tudo ser
abordado com maiores detalhes nos captulos seguintes.

Mtodos Assncronos

A Microsoft incorporou diretamente no C# e no VB.NET o suporte para programao


assncrona. A ideia facilitar a programao assncrona, que no era nada trivial at o
momento, tornando a escrita de um cdigo assncrono muito prximo a escrita de um
cdigo sncrono, e nos bastidores, o compilador faz grande parte do trabalho. Grande
parte das funcionalidades do .NET Framework que j possuem suporte nativo ao
consumo em formato assncrono, foram readaptados para que assim, os
desenvolvedores possam fazer uso dos novos recursos oferecidos pela linguagem para
consumi-los.

Com o ASP.NET Web API tambm podemos fazer com que os mtodos expostos pela
API sejam processados assincronamente, usufruindo de todos os benefcios de um
mtodo ser executado de forma assncrona.

Vamos supor que o nosso servio de Artistas deve recorrer um segundo servio para
extrair as notcias referentes um determinado artista. No interior do mtodo que
retorna o artista, faremos a chamada para o servio de Notcias e esperamos pelo

20
resultado, que ao voltar, efetuamos o parser e, finalmente, convertemos para o formato
esperado e retornamos ao cliente.

Ao executar este tipo de servio, a requisio ser bloqueada pelo runtime at que o
resultado seja devolvido para o servio. Isso prejudica, e muito, a escalabilidade do
servio. O fato da thread ficar bloqueada enquanto espera pelas notcias, ela poderia
estar atendendo outras requisies, que talvez no exijam recursos de terceiros (I/O
bound). O fato de disponibilizar a thread para que ela possa atender outras requisies,
faro com que elas no esperem por um tempo indeterminado, pois como dependemos
do resultado de um terceiro, poderamos arranjar muito trabalho para esta thread, at
que ela precise retomar o trabalho da requisio anterior.

Para implementar o controller da API de forma assncrona, exigir algumas mudanas,


mas nada que faa com que seja necessrio escrever e/ou gerenciar uma poro de
cdigo para garantir o assincronismo (IAsyncResult por exemplo). Com isso, o primeiro
detalhe a notar na escrita da ao assncrona, a exigncia da keyword async, que faz
do C#.

public class ArtistasController : ApiController


{
[HttpGet]
public async Task<Artista> Recuperar(int id)
{
var artista = this.repositorio.Buscar(id);

using (var client = new HttpClient())


artista.Noticias =
await
(await client.GetAsync(ServicoDeNoticias))
.Content
.ReadAsAsync<IEnumerable<Noticia>>();

return artista;
}
}

Tratamento de Erros

Durante a execuo, uma poro de excees podem acontecer, sejam elas referentes
infraestrutura ou at mesmo alguma regra de negcio, e o no tratamento correto
delas, far com as mesmas no sejam propagadas corretamente ao cliente que consome
a API. A maior preocupao aqui mapear o problema ocorrido para algum cdigo HTTP
correspondente.

Isso se faz necessrio porque excees so caractersticas de plataforma, e precisamos


de alguma forma expressar isso atravs de algum elemento do HTTP, para que cada um
dos mais variados clientes possam interpretar de uma forma especfica. Por padro,
todos os erros que ocorrem no servio e no tratados, retornando ao cliente o cdigo
de status 500, que indica um erro interno do servio (Internal Server Error).

O ASP.NET Web API possui uma exceo chamada HttpResponseException, que quando
instanciada definimos em seu construtor o cdigo de status do HTTP indicando o erro

21
que ocorreu. Para exemplificar o uso deste tipo, podemos disparar o erro 404 (Not
Found) se o cliente est solicitando um artista que no existe.

public class ArtistasController : ApiController


{
[HttpGet]
public Artista Recuperar(int id)
{
var artista = this.repositorio.Buscar(id);

if (artista == null)
throw new HttpResponseException(
new HttpResponseMessage(HttpStatusCode.NotFound)
{
Content = new StringContent("Artista no encontrado"),
ReasonPhrase = "Id Invlido"
});

return artista;
}
}

Ainda como opo temos a classe HttpError para expressar o problema que ocorreu
dentro do mtodo. A principal vantagem de utilizar esta classe em relao aquele que
vimos acima, que o contedo que identifica o erro serializado no corpo da
mensagem, seguindo as regras de negociao de contedo.

public class ArtistasController : ApiController


{
[HttpGet]
public HttpResponseMessage Recuperar(int id)
{
var artista = this.repositorio.Buscar(id);

if (artista == null)
return Request.CreateErrorResponse(
HttpStatusCode.NotFound,
new HttpError("Artista no encontrado"));
else
return Request.CreateResponse(HttpStatusCode.OK, artista);
}
}

Tratar as excees in-place (como acima) pode no ser uma sada elegante, devido a
redundncia de cdigo. Para facilitar, podemos centralizar o tratamento em nvel de
aplicao, o que permitir com que qualquer exceo no tratada no interior da ao,
ser capturada por este tratador, que por sua vez analisar o erro ocorrido, podendo
efetuar algum tipo de logging e, finalmente, encaminhar o problema ao cliente. neste
momento que podemos efetuar alguma espcie de traduo, para tornar a resposta
coerente ao que determina os cdigos do HTTP, como por exemplo: se algum erro
relacionado autorizao, devemos definir como resposta 403 (Forbidden); j se algum
informao est faltante (assim como vimos no exemplo acima), devemos retornar o
status 400 (Bad Request); j se o registro procurado no foi encontrado, ele dever
receber o cdigo 404 (Not Found), e assim por diante.

22
Para isso vamos recorrer a criao de um filtro customizado para centralizar a traduo
de algum problema que acontecer. S que neste caso, temos uma classe abstrata
chamada de ExceptionFilterAttribute, que j fornece parte da infraestrutura necessria
para o tratamento de erros que ocorrem, e equivalente ao atributo
HandleErrorAttribute que temos no ASP.NET MVC. Tudo o que precisamos fazer aqui
sobrescrever o mtodo OnException e definir toda a regra de traduo necessria.
Abaixo um exemplo simples de como proceder para realizar esta customizao:

public class ExceptionTranslatorAttribute : ExceptionFilterAttribute


{
public override void OnException(HttpActionExecutedContext ctx)
{
var errorDetails = new ErrorDetails();
var statusCode = HttpStatusCode.InternalServerError;

if (ctx.Exception is HttpException)
{
var httpEx = (HttpException)ctx.Exception;

errorDetails.Message = httpEx.Message;
statusCode = (HttpStatusCode)httpEx.GetHttpCode();
}
else
{
errorDetails.Message = "** Internal Server Error **";
}

ctx.Result =
new HttpResponseMessage<ErrorDetails>(errorDetails, statusCode);
}
}

No vamos se aprofundar muito aqui, mas a criao de filtros um ponto de


estensibilidade, e que teremos um captulo especfico para abordar este assunto. O que
precisamos nos atentar aqui existem vrios escopos para registros um filtro deste tipo,
podendo ele ser aplicado em nvel de ao, de controller ou globalmente.

O cdigo abaixo registra o tradutor de excees em nvel global, recorrendo ao arquivo


Global.asax para isso, que ser utilizado por todo e qualquer API que estiver abaixo
deste projeto. Maiores detalhes sobre a configurao de servio, sero abordados em
breve, ainda neste captulo.

GlobalConfiguration
.Configuration
.Filters
.Add(new ExceptionTranslatorAttribute());

Validaes

Como vimos anteriormente, o ASP.NET Web API capaz de construir um objeto


complexo baseado no corpo da requisio. Mas como acontece em qualquer aplicao,
pode ser que o objeto esteja com um valores invlidos, o que impedir do mesmo ser
processado corretamente.

23
Mesma se tratando de servios onde o foco a integrao entre aplicaes,
necessrio que se faa a validao, para garantir que a requisio tenha as informaes
corretas para ser processada.

Uma das opes que temos para isso, fazer como j realizamos no ASP.NET MVC:
recorrer aos Data Annotations do .NET Framework para validar se o objeto encontra-se
em um estado vlido. Para isso, basta decorarmos as propriedades com os mais variados
atributos que existem debaixo do namespace (e assembly)
System.ComponentModel.DataAnnotations.

Para iniciar devemos referenciar em nosso projeto o assembly que contm os tipos para
a validao: System.ComponentModel.DataAnnotations.dll. A partir do momento em
que referenciamos este assembly na aplicao, podemos aplicar em nossos objetos os
atributos que determinam as regras que cada propriedade dever respeitar. No exemplo
abaixo ilustra estamos informando ao ASP.NET que a propriedade Nome deve ser
preenchida e a propriedade e-mail deve representar um endereo de e-mail em formato
vlido.

public class Artista


{
public int Id { get; set; }

[Required]
public string Nome { get; set; }

[EmailAddress]
public string Email { get; set; }
}

S que os atributos no funcionam por si s. O ASP.NET Web API j est preparado para
realizar a validao do objeto que est sendo postado, avaliando se cada propriedade
do mesmo est seguindo os atributos aplicados ela.

Como o ASP.NET j realiza toda a validao, o que nos resta no interior do mtodo
verificar se o objeto est vlido. A classe ApiController fornece uma propriedade
chamada ModelState. Essa propriedade d ao controller a possibilidade de verificar se o
modelo que est sendo postado est ou no valido atravs da propriedade boleana
IsValid, e alm disso, nos permite acessar as propriedades problemticas, ou melhor,
aquelas que no passaram na validao, que est baseada nos atributos que foram
aplicados.

Abaixo estamos avaliando essa propriedade, e se houver alguma informao errada,


retornamos ao cliente o cdigo 400 (Bad Request), indicando que h problemas na
requisio que foi encaminhada para o servio. O que importante notar que o
mtodo que recebe e trata a requisio no possui regras de validao para o objeto.
Isso acabou sendo terceirizado para os Data Annotations do .NET, que acabam
realizando toda a validao em estgios anteriores ao processamento da requisio, e
com isso o mtodo fica apenas com a responsabilidade de processar se a requisio foi
encaminhada da forma correta.

24
public class ArtistasController : ApiController
{
[HttpPost]
public HttpResponseMessage Adicionar(Artista artista)
{
if (ModelState.IsValid)
{
//...
return new HttpResponseMessage(HttpStatusCode.Created);
}

return new HttpResponseMessage(HttpStatusCode.BadRequest);


}
}

Configurao

Ao trabalhar com algum tipo de projeto .NET, estamos acostumados a lidar com a
configurao e estensibilidade do mesmo utilizando os arquivos de configurao
(App.config ou Web.config). O ASP.NET Web API trouxe toda a configurao para ser
realizada atravs do modelo imperativo (via cdigo) ao invs do modelo declarativo (via
Xml).

Para centralizar toda a configurao das APIs, temos a disposio um objeto global que
possui uma variedade de mtodos para registrarmos todos os elementos que podemos
customizar. Toda essa configurao realizada a partir do mtodo Application_Start do
arquivo Global.asax. Como a template do projeto segue a mesma linha do ASP.NET MVC,
a configurao das APIs so realizadas em uma classe esttica chamada WebApiConfig,
que recebe como parmetro um objeto do tipo HttpConfiguration, acessvel atravs da
propriedade esttica Configuration da classe GlobalConfiguration.

public class WebApiApplication : System.Web.HttpApplication


{
protected void Application_Start()
{
WebApiConfig.Register(GlobalConfiguration.Configuration);
}
}

public static class WebApiConfig


{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}

Inicialmente o configurador das APIs possui apenas um cdigo que registra a rota padro
para que as requisies sejam encaminhadas corretamente para os mtodos. No
vamos nos estender aqui, pois h um captulo dedicado a este assunto. A classe
HttpConfiguration possui uma srie de propriedades que sero exploradas ao longo dos
prximos captulos.

25
Elementos do HTTP

Alm das informaes que so enviadas e recebidas atravs do corpo da mensagem,


podemos recorrer alguns elementos inerentes ao HTTP, para incluir informaes que
fazem parte da requisio, como por exemplo, ID para controle da segurana, tags para
caching, etc.

Para essas informaes, podemos recorrer aos famosos elementos do HTTP que so a
coleo de headers, de querystrings e cookies. Como falamos anteriormente, se
quisermos ter o controle da mensagem, o mtodo/ao deve lidar diretamente com as
classes HttpRequestMessage e HttpResponseMessage. Esses objetos expem
propriedades para acesso estes recursos, e mtodos de estenso facilitam o acesso a
estas informaes.

O cookie nada mais que um header dentro da requisio, que quando o servio
adiciona um cookie, chega uma instruo (header) ao cliente chamado Set-Cookie, que
faz com que o mesmo seja salvo e adicionado nas futuras requisies. No ASP.NET Web
API temos uma classe chamada CookieHeaderValue, que representa um cookie, que
depois de criado, podemos adicionar na coleo de cookies da resposta e entregar ao
cliente.

[HttpGet]
public HttpResponseMessage Ping(HttpRequestMessage request)
{
var response = new HttpResponseMessage(HttpStatusCode.OK);
var id = request.Headers.GetCookies("Id").FirstOrDefault();

if (id == null)
{
response.Headers.AddCookies(new CookieHeaderValue[]
{
new CookieHeaderValue("Id", Guid.NewGuid().ToString())
{
Expires = DateTimeOffset.Now.AddDays(10)
}
});
}

return response;
}

Figura 5 - Cookie sendo levado para o cliente.

26
Ao realizar a requisio, temos o header Set-Cookie sendo devolvido, que competir ao
cliente que est acessando, salv-lo para enviar em futuras requisies. Se fizermos isso
com o Fiddler, podemos perceber que quando a ao executada, o header Cookie
interpretado e entregue ao ASP.NET Web API como uma instncia da casse
CookieHeaderValue.

Figura 6 - Cookie sendo retornado para o servio.

No exemplo acima apenas estamos lidando com um nico valor, mas nada impede de
termos uma informao mais estruturada dentro do cookie, ou seja, podemos
armazenar diversos dados. A classe CookieHeaderValue possui um construtor que
permite informar uma coleo do tipo NameValueCollection, que define uma lista de
valores nomeados, onde podemos adicionar todos elementos que queremos que sejam
levado ao cliente, e que sero separados pelo caracter &.

[HttpGet]
public HttpResponseMessage Ping(HttpRequestMessage request)
{
var response = new HttpResponseMessage(HttpStatusCode.OK);
var info = request.Headers.GetCookies("Info").FirstOrDefault();

if (info == null)
{
var data = new NameValueCollection();
data["Id"] = Guid.NewGuid().ToString();
data["Type"] = "Simplex";
data["Server"] = "SRV01";

response.Headers.AddCookies(new CookieHeaderValue[]
{
new CookieHeaderValue("Info", data)
});
}

return response;
}

27
Figura 7 - Cookie com mltiplos valores.

Documentao

Quando estamos falando de servios baseados em SOAP, temos um documento


comando de WSDL (Web Service Description Language) baseado em XML, que descreve
todas as caractersticas (definies) de um determinado servio. justamente esse
documento que utilizado por ferramentas como o svcutil.exe e a opo "Add Service
Reference" do Visual Studio, para gerar uma classe que representar o proxy, que por
sua vez, ser utilizado pelos clientes para consumir o servio como se fosse uma classe
local, mas durante a execuo, a mensagem ser enviada ao ponto remoto.

Mas importante dizer que mesmo servios baseados em REST, tambm precisam, de
alguma forma, expor alguma espcie de documentao, para descrever as aes que as
APIs esto disponibilizando aos consumidores, apontando o caminho (URI) at aquele
ponto, mtodo/verbo (HTTP), informaes que precisam ser passadas, formatos
suportados, etc.

A ideia apenas ser apenas informativo, ou seja, isso no ser utilizado pelo cliente para
a criao automtica de um proxy. Pensando nisso, a Microsoft incluiu no ASP.NET Web
API a opo para gerar e customizar as documentaes de uma API.

Mas a documentao sempre exibida, na maioria das vezes, de forma amigvel ao


consumidor, para que ele possa entender cada uma das aes, suas exigncias, para que
ele possa construir as requisies da forma correta. Sendo assim, podemos na prpria
aplicao onde ns temos as APIs, criar um controller que retorna uma view (HTML),
contendo a descrio das APIs que esto sendo hospedadas naquela mesma aplicao.

public class DeveloperController : Controller


{
public ActionResult Apis()
{
var explorer = GlobalConfiguration.Configuration.Services.GetApiExplorer();

return View(explorer.ApiDescriptions);
}
}

Note que estamos recorrendo ao mtodo GetApiExplorer, disponibilizado atravs da


configurao global das APIs. Este mtodo retorna um objeto que implementa a
interface IApiExplorer, que como o prprio nome sugere, define a estrutura que permite
obter a descrio das APIs. Nativamente j temos uma implementao chamada
ApiExplorer, que materializa todoas as APIs em instncias da classe ApiDescription, e

28
uma coleo deste objeto retornada atravs da propriedade ApiDescriptions, e que
repassamos para que a view possa renderizar isso.

Na view, tudo o que precisamos fazer iterar pelo modelo, e cada elemento dentro
deste lao representa uma ao especfica que est dentro da API. A classe que
representa a ao, possui vrias propriedades, fornecendo tudo o que necessrio para
que os clientes possam consumir qualquer ums destas aes. Abaixo temos o cdigo
que percorre e exibe cada uma delas:

@model IEnumerable<System.Web.Http.Description.ApiDescription>
<body>
@foreach (var descriptor in this.Model)
{
<ul>
<li><b>@descriptor.HttpMethod - @descriptor.RelativePath</b></li>
<li>Documentation: @descriptor.Documentation</li>

@if (descriptor.SupportedResponseFormatters.Count > 0)


{
<li>Media Types
<ul>
@foreach (var mediaType in
descriptor.SupportedResponseFormatters.Select(
mt => mt.SupportedMediaTypes.First().MediaType))
{
<li>@mediaType</li>
}
</ul>
</li>
}

@if (descriptor.ParameterDescriptions.Count > 0)


{
<li>Parameters
<ul>
@foreach (var parameter in descriptor.ParameterDescriptions)
{
<li>Name: @parameter.Name</li>
<li>Type: @parameter.ParameterDescriptor.ParameterType</li>
<li>Source: @parameter.Source</li>
}
</ul>
</li>
}
</ul>
}
</body>

Ao acessar essa view no navegador, temos a relao de todas as aes que esto
expostas pelas APIs. A visibilidade das aes controlada a partir do atributo
ApiExplorerSettingsAttribute, que possui uma propriedade boleana chamada IgnoreApi,
que quando definida como True, omite a extrao e, consequentemente, a sua
visualizao.

29
Figura 8 - Documentao sendo exibida no browser.

importante notar que na imagem acima, estamos apresentando a propriedade


Documentation. A mensagem que aparece ali uma customizao que podemos fazer
para prover essa informao, extraindo-a de algum lugar. Para definir a descrio da
ao, vamos criar um atributo customizado para que quando decorado no mtodo, ele
ser extrado por parte da infraestrutura do ASP.NET, alimentando a propriedade
Documentation. O primeiro passo, consiste na criao de um atributo para definir a
mensagem:

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]


public class ApiDocumentationAttribute : Attribute
{
public ApiDocumentationAttribute(string message)
{
this.Message = message;
}

public string Message { get; private set; }


}

O prximo passo decor-lo em cada uma das aes que quisermos apresentar uma
informao/descrio. A classe abaixo representa a nossa API, e o atributo
recentemente criado foi decorado em todas as aes, descrevendo suas respectivas
funcionalidades:

public class ClientesController : ApiController


{
[ApiDocumentation("Retorna todos os clientes.")]
public IEnumerable<Cliente> Get()
{
//...
}

[ApiDocumentation("Retorna um cliente pelo seu Id.")]


public Cliente Get(int id)
{
//...
}

[ApiDocumentation("Inclui um novo cliente.")]


public void Post(Cliente cliente)

30
{
//...
}

[ApiDocumentation("Exclui um cliente existente.")]


public void Delete(int id)
{
//...
}
}

S que o atributo por si s no funciona. Precisamos de algum elemento para extrair


essa customizao que fizemos, e para isso, a temos uma segunda interface, chamada
IDocumentationProvider, que fornece dois mtodos com o mesmo nome:
GetDocumentation. A diferena entre eles o parmetro que cada um deles recebe. O
primeiro recebe um parmetro do tipo HttpParameterDescriptor, o que permitir
descrever, tambm, cada um dos parmetros de uma determinada ao. J o segundo
mtodo, recebe um parmetro do tipo HttpActionDescriptor, qual utilizaremos para
extrair as informaes pertinentes uma ao especfica.

public class ApiDocumentationAttributeProvider : IdocumentationProvider


{
public string GetDocumentation(HttpParameterDescriptor parameterDescriptor)
{
return null;
}

public string GetDocumentation(HttpActionDescriptor actionDescriptor)


{
var attributes =
actionDescriptor.GetCustomAttributes<ApiDocumentationAttribute>();

if (attributes.Count > 0)
return attributes.First().Message;

return null;
}
}

Aqui extramos o atributo que criamos, e se ele for encontrado, retornamos o valor
definido na propriedade Message. A ausncia deste atributo, faz com que um valor nulo
seja retornado, fazendo com que nenhuma informao extra seja includa para a ao.

E, finalmente, para incluir o provedor de documentao ao runtime do ASP.NET Web


API, recorremos configurao das APIs, substituindo qualquer implementao
existente para este servio, para o nosso provedor que extra a documentao do
atributo customizado.

GlobalConfiguration.Configuration.Services.Replace(
typeof(IDocumentationProvider),
new ApiDocumentationAttributeProvider());

31
Roteamento
No nicio foi comentado que uma das caracterstica dos servios REST, que todo
recurso enderevel atravs de uma URI (Universal Resource Identifier). atravs da
URI que sabemos onde ele est localizado e, consequentemente, conseguiremos chegar
at ele recurso e executar uma determinada ao.

Cada URI identifica um recurso especfico, e ela tem uma sintaxe que bastante comum
para os desenvolvedores: [scheme]:[port]://[host]/[path][?query]. Cada pedao dela
tem uma representao e funcionalidade, que esto detalhes na listagem abaixo:

Scheme: Identifica o protocolo que ser utilizado para realizar a requisio


algum recurso, podendo ser: HTTP, HTTPS, FTP, etc.
Port: Opo para definir o nmero da porta (no destino) que ser utilizada para
receber a requisio. Se omitido, utilizar a porta padro do protocolo, onde no
HTTP a porte 80, no HTTPS a porta 443, etc.
Host: O Host define o nome (fornecido pelo DNS) ou o endereo IP do servidor.
Path: Esta parte da URI qual identifica o recurso em si. atravs dele que
apontamos qual dos recursos que desejamos acesso dentro daquele servidor.
Query: Trata-se de uma informao opcional que pode ser encaminhada para o
servio, fornecendo informaes adicionais para o processamento da requisio.
Um exemplo disso incluir o identificador do recurso que est sendo solicitado.

At pouco tempo atrs as URI eram algo indecifrvel para o usurio final, sendo apenas
um endereo para algum recurso (seja ele qual for) em um ponto da rede. Aos poucos
as URIs foram ficando cada vez mais legvel, ou seja, tendo a mesma funcionalidade mas
sendo mais amigvel, o que facilita o retorno do usurio, ou ainda, a prpria URI refletir
o que ela representa. H tambm benefcios relacionados ao SEO (Search Engine
Optimization), onde os buscadores consideram as palavras encontradas na URI durante
a pesquisa.

Durante o desenvolvimento do ASP.NET MVC, a Microsoft criou dentro dele um


mecanismo de roteamento, que baseado em uma tabela de regras, ele capaz de
interpretar a requisio (URI) que est chegando para o mesmo e identificar o local, o
servio, a classe e o mtodo a ser executado. Antes mesmo do lanamento oficial do
ASP.NET MVC, a Microsoft fez com que este recurso de roteamento fosse desacoplado
e levado para o core do ASP.NET, e com isso, pode ser utilizado pelo ASP.NET MVC, Web
Forms e tambm pelo ASP.NET Web API, que o nosso foco aqui.

Tudo comea pela configurao dessa tabela de regras que est localizada no arquivo
Global.asax. Como sabemos, ao rodar a aplicao pela primeira vez, o evento
Application_Start disparado, e justamente dentro dele onde o cdigo que faz toda a
configurao das rotas colocada.

O objeto de configurao fornece uma coleo de rotas, e que na template de projeto


que estamos utilizando, a rota padro colocada no arquivo WebApiConfig. Notamos
que a rota padro possui o nome de DefaultApi, e existe um segmento na seo Path

32
da URI chamado de api. Ele utilizado para diferenciar e no causar conflito com
outras eventuais rotas que j existam naquela aplicao, como por exemplo, aquelas
que so criadas pelo projeto ASP.NET MVC. Essa necessidade se deve pelo fato de que
podemos hospedar debaixo de um mesmo projeto, controllers que renderizam views
(HTML) bem como controllers que retornam dados (Web API).

public static class WebApiConfig


{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}

Toda rota pode ser composta de literais e de placeholders, que so substitudos durante
a execuo. No exemplo acima, api trata-se de um literal, enquanto o {controller} e
{id} so os placeholders. Quando a requisio realizada, o ASP.NET tenta mapear os
valores extrados da URL e preencher os placeholders colocados na rota. Caso nenhuma
rota se enquadre com a requisio que est solicitada, o erro 404 (Not Found)
retornado ao cliente.

importante mencionar que os placeholders podem ter valor padro definido. isso
que define o ltimo parmetro do mtodo MapHttpRoute, chamado defaults. Podemos
determinar se ele opcional, e definir um valor padro se ele for omitido durante a
requisio atravs de um dicionrio, onde cada item corresponde ao nome do
placeholder e seu respectivo valor. Abaixo temos algumas URLs indicando se ela est ou
no enquadrada na rota padro:

URL Mtodo

api/Artistas/MaxPezzali ArtistasController.Get(MaxPezzali)

api/Artistas/34 ArtistasController.Get(34)

Artistas/Eros Como no h o sufixo api/, ele no se enquadrar na


rota padro, rejeitando-a.

api/Artistas ArtistasController.Get() e o parmetro id ser nulo.

Para o exemplo acima, estamos utilizando o seguinte mtodo:

33
public Artista Get(string id = "") { }

Por conveno, se o mtodo for nomeado com o verbo do HTTP, automaticamente o


ASP.NET Web API entrega a requisio naquela verbo paa ele, sem qualquer trabalho
adicional para que isso ocorra.

Durante a execuo o processo de roteamento possui alguns estgios de processamento


que so executados at que a ao seja de fato executada. O primeiro passo consiste ao
enquadramento da URI uma rota configurada na tabela de roteamento. Se
encontrada, as informaes colocadas na URI so extradas e adicionadas no dicionrio
de rotas, que podero ser utilizadas por toda a requisio, sendo pelo ASP.NET Web API
(runtime) ou pelo cdigo customizado.

Depois de alguma rota encontrada, comea o processo para identificar qual a ao, ou
melhor, o mtodo que o cliente est solicitando. S que antes de disso, necessrio
identificar a classe (controller) onde ele est. Como a rota padro j vem configurada no
projeto, os dois placeholders determinam indiretamente a classe (controller) e o mtodo
(ao), competindo ao ASP.NET realizar o parser dos fragmentos da URI, encontrar a
classe e o mtodo, e depois disso, abastecer os parmetros (caso eles existam) e,
finalmente, invocar o mtodo, retornando o resultado (sucesso ou falha) ao cliente
solicitante.

Apesar do compilador no indicar, toda a classe que ser considerada uma API,
necessrio que ela no seja abstrata e tenha o seu modificador de acesso definido como
pblico, caso contrrio, o ASP.NET Web API no ser capaz de instanci-la. E, finalmente,
apesar de termos a necessidade do sufixo Controller nas classes, essa palavra no est
presente na URI. Isso apenas uma exigncia do ASP.NET Web API, para identificar quais
classes dentro do projeto correspondem uma API.

Depois de encontrada a classe, o momento de escolher o mtodo a ser executado. Da


mesma forma que a classe, o mtodo a ser executado tambm escolhido baseado na
URI da requisio. Pela afinidade ao HTTP, a busca do mtodo dentro da classe considera
os verbos do HTTP (GET, POST, PUT, DELETE, etc.) durante a busca. O algoritmo de
pesquisa do mtodo dentro do controller segue os passos descritos abaixo:

1. Seleciona todos os mtodos do controller que se enquadram com o verbo do


HTTP da requisio. O mtodo pode ser nomeado ou prefixado apenas com o
nome do verbo.
2. Remove aquelas aes com o nome diferente do valor que est no atributo
action do dicionrio de rotas.
3. Tentar realizar o mapeamento dos parmetros, onde os tipos simples so
extrados da URI, enquanto tipos complexos so extrados do corpo da
mensagem.
a. Para cada ao, extrai uma lista de parmetros de tipos simples, e exceto
os parmetros opcionais, tenta encontrar o valor de cada um deles da
URI.

34
b. Dessa lista tenta encontrar o respectivo valor no dicionrio de rotas ou
na querystring da URI, independente de case ou de ordem dos
parmetros.
c. Seleciona aquela ao onde cada um dos parmetros encontrado na
URI.
4. Ignora as aes que esto decoradas com o atributo NonActionAttribute.

Como notamos no algoritmo acima, ele no considera a busca de aes quando h tipos
complexos. A ideia tentar encontrar uma ao atravs da descrio esttica da
mensagem, ou seja, sem a necessidade de recorrer a qualquer mecanismo extra. Caso
isso no seja suficiente, o ASP.NET Web API recorrer um binder ou um formatador,
baseado na descrio do parmetro e que na maioria das vezes, oriundo a partir do
corpo da mensagem.

E o mtodo MapHttpRoute ainda fornece um outro parmetro que nos permite


especificar constraints. Atravs delas podemos determinar um validador para um
parmetro especfico, ou seja, se conseguimos antecipar qual o formato que a
informao deve ser colocada, isso evitar que ela seja rejeitada logo nos primeiros
estgios do processamento, retornando o erro 404 (Not Found).

public static class WebApiConfig


{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{periodo}",
defaults: new { periodo = DateTime.Now.ToString("yyyy-MM") },
constraints: new { periodo = @"[0-9]{4}\-[0-9]{2}" }
);
}
}

Da mesma forma que fazemos com os valores padro para cada placeholder, criamos
um novo dicionrio onde a chave o nome do parmetro, e o valor uma expresso
regular que determina o formato em que o parmetro deve ter. O fato de adicionar isso,
o prprio ASP.NET Web API se encarrega de avaliar se o valor dos parmetros se
enquadram com a regra determinada na expresso regular. Isso nos d a chance de
separar as validaes do mtodo que executa a ao, ficando responsvel apenas por
lidar com a regra de negcio.

Depurando Rotas

Acima vimos como podemos configurar as rotas no projeto, mas no estamos limitados
a incluir apenas uma opo de roteamento. Na medida em que as APIs vo sendo
construdas, voc est livre para criar rotas especficas para recepcionar as requisies.

A medida em que as rotas vo sendo adicionadas, podemos enfrentar alguma


dificuldade no desenvolvimento, onde a requisio no chega ao destino esperado, no

35
encontrando o controller ou a ao, ou at mesmo, em casos mais extremos, se
enquadrando em uma rota diferente daquela que estvamos imaginando.

Para facilitar a depurao disso, existe uma ferramenta chamada ASP.NET Web API
Route Debugger, que pode ser adicionado aplicao atravs do Nuget. Para adicion-
la ao projeto, basta executar o comando abaixo na Package Manager Console, conforme
mostrado abaixo:

PM> Install-Package WebApiRouteDebugger

Ao rodar este comando, alguns elementos so includos no projeto. Basicamente trata-


se de uma nova rea, que possui a interface grfica para exibir o resultado da requisio
com os parmetros e resultados da interceptao que foi realizada pelo debugger.

Depois de instalar este depurador, basta rodarmos a aplicao e quando chegarmos no


navegador, basta acrescentarmos na URL o sufixo /rd. Isso far com que uma tela seja
exibida para que voc digite o endereo completo para a API que deseja invocar.

Figura 9 - Route Debbuger.

A partir desta tela podemos ir testando as URIs que temos para validar se alguma rota
dentro deste projeto consegue ser encontrada e, consequentemente, direcionada para
o mtodo que tratar a requisio. Quando pressionamos o boto Send, um resumo
como o resultado da avaliao exibido, e nele voc conseguir analisar de forma
simples as informaes que foram extradas e facilmente identificar onde est o
problema.

Entre as informaes, ele exibe o dicionrio de dados que foi extrado da URI. Ele elenca
as informao (chave e valor), quais voc poder avaliar se o valor informado na URI
est, corretamente, abastacendo o parmetro desejado.

A prxima tabela aponta as rotas que esto configuradas no projeto, incluindo as


informaes extras, tais como: valores padro, constraints, etc. Com as informaes que
compem a configurao da rota sendo colocada aqui, fica fcil determinar o porque os
parmetros entraram ou no, porque eles os parmetros assumiram o valor padro ao
invs de receber aquele que est na URI, e assim por diante.

36
Entre as duas ltimas tabelas temos a primeira que lista todos os controllers que esto
adicionados ao projeto, bem como o seu tipo, namespace e assembly. J a segunda, e
no menos importante, exibe todas as aes que foram localizadas, descrevendo-as
complementos, incluindo o verbo HTTP que ela atende, o seu nome e o(s) parmetro(s).
Logo na sequncia, ele nos aponta se ao (mtodo) foi encontrado pelo nome (By
Action Name) ou pelo verbo (By HTTP Verb). A imagem abaixo ilustra essa tela com todos
os detalhes descritos aqui.

Figura 10 - Route Debugger exibindo as informaes.

Para a grande maioria das tarefas discutidas neste captulo, existem objetos
responsveis por executar cada uma delas, e que podemos customizar cada um deles
para que seja possvel mudarmos algumas regras ou interceptarmos os estgios do
processamento e incluir um cdigo para efetuar logs, mensurar performance, etc. A
estensibilidade abordada em detalhes em um captulo mais adiante.

Rotas Declarativas

O modelo de roteamento que vimos at aqui baseado em uma conveno que


definida atravs de templates e esto centralizadas arquivo Global.asax. Como falamos
acima, durante a execuo os placeholders so substitudos pelos parmetros que so

37
extrados, na maioria das vezes, da URI e, consequentemente, encaminhada para a ao
dentro do controller. Por ser uma coleo, podemos predefinir vrias rotas para atender
todas as URIs que so criadas para as APIs que rodam dentro daquela aplicao.

Apesar da centralizao ser um ponto positivo, comea a ficar complicado quando o


nmero de rotas criadas comea a crescer. Haver um trabalho em olhar para essa
tabela e analisar qual das rotas a ao se enquadra. Nem sempre haver uma rota
genrica para atender todas as requisies, j que para expressar melhor a estrutura e
hirarquia dos recursos, teremos que definir a rota para cada ao contida no controller.

para este fim que a Microsoft incluiu no ASP.NET Web API uma funcionalidade
chamada de attribute routing, ou roteamento declativo. A ideia aqui configurar o
roteamento para uma ao em um local mais prximo dela, para alm de permitir a
configurao especfica, facilitar a manuteno.

A implementao bastante simples mas muito poderosa. Aqueles atributos que vimos
acima que determinam atravs de que verbo do HTTP a ao estar acessvel
(HttpGetAttribute, HttpPutAttribute, HttpPostAttribute, HttpDeleteAttribute, etc.),
passam a ter um overload no construtor que aceita uma string com a template da rota
que ser atendida por aquela ao (mtodo).

public class ArtistasController : ApiController


{
[HttpGet("artistas/{nomeDoArtista}/albuns")]
public IEnumerable<Album> RecuperarAlbuns(string nomeDoArtista)
{
return new[]
{
new Album() { Titulo = "Max 20" },
new Album() { Titulo = "Terraferma" }
};
}
}

No exemplo acima vemos que a rota foi configurada in-place, ou seja, no prprio local
onde a ao foi criada. Da mesma forma que fazemos na definio da rota no arquivo
Global.asax, aqui tambm podemos utilizar placeholders, para que eles sejam
substitudos pelos parmetros da prpria ao que, novamente, so extrados da
requisio.

Mas aplicar os atributos com as rotas no suficiente. H a necessidade de instruir o


ASP.NET a coletar as informaes sobre o roteamento diretamente nas aes. Para isso
h um mtodo de estenso que aplicado classe HttpConfiguration chamado
MapHttpAttributeRoutes no arquivo Global.asax:

config.MapHttpAttributeRoutes();

O resultado final para a chamada desta ao fica:

38
http://localhost:49170/artistas/MaxPezzali/albuns

claro que o controller pode conter diversas outras aes, onde cada uma delas retorna
outras informaes, neste caso, de um determinado artista. Suponhamos que tambm
teremos uma ao que retorne as notcias do artista. Bastaria adicionar o mtodo
classe, configurar o roteamento apenas alterando a ltima parte , trocando albuns por
noticias.

H tambm uma opo para elevar o prefixo das rotas para o nvel da classe (controller).
Para isso, utilizaremos um atributo chamado RoutePrefixAttribute que nos permite
definir um valor que ser combinado com as rotas configuradas ao por ao para
compor a rota final de acesso para cada uma delas.

[RoutePrefix("artistas")]
public class ArtistasController : ApiController
{
[HttpGet("{nomeDoArtista}/albuns")]
public IEnumerable<Album> RecuperarAlbuns(string nomeDoArtista)
{
return new[]
{
new Album() { Titulo = "Max 20" },
new Album() { Titulo = "Terraferma" }
};
}

[HttpGet("{nomeDoArtista}/noticias")]
public IEnumerable<Noticia> RecuperarNoticias(string nomeDoArtista)
{
return new[]
{
new Noticia() { Titulo = "Novo Album em 2013" }
};
}
}

O fato de configurarmos as rotas nas aes, no quer dizer que perderemos certas
funcionalidades. Mesmo utilizando esta tcnica, teremos a possibilidade de configurar
valores padro para os parmetros, bem como constraints para garantir que o cliente
informe os dados seguindo uma regra j estabelecida.

Para ambos os casos, teremos uma sintaxe ligeiramente diferente comparada ao


modelo tradicional (centralizado, de forma imperativa). O prprio placeholder ir
contemplar os valores padro e as constraints. Para casos onde teremos um parmetro
opcional e desejarmos definir um valor padro, teremos das formas para representar,
onde a primeira delas basta utilizar o recurso do prprio C# para isso, e no placeholder
sufixar o parmetro com o caracter ?.

[HttpGet("artistas/noticias/{cultura?}")]
public IEnumerable<Noticia> RecuperarNoticias(string cultura = "pt-BR") { }

[HttpGet("artistas/noticias/{cultura=pt-BR}")]
public IEnumerable<Noticia> RecuperarNoticias(string cultura) { }

39
J a segunda forma, definimos o valor padro do parmetro no prprio placeholder, que
ponto de vista daquele que est acessando a cultura de dentro da ao, no muda em
nada. A diferena que no segundo caso, o valor ser encaminhado para o model binder,
onde voc poder fazer algo diferente se assim desejar.

No caso das constraints temos um conjunto de opes e funes que garantem que os
parmetros informados pelo cliente se enquadrem com a exigncia da API. A ideia
definir na configurao da rota a constraint usando a seguinte sintaxe:
{parametro:contraint}. Na primeira parte definiremos o nome do parmetro que est
declarado na assinatura do mtodo (ao), e na opo constraint iremos escolher uma
das vrias opes predefinidas que temos a nossa disposio:

Constraint Descrio Exemplo

alpha, datetime, bool, Garante com que o {cultura:alpha}


guid parmetro seja
alfanumrico (a-z, A-Z).
H tambm opes para
tipos de dados especiais.

int, decimal, double, Opes para nmeros de {pagina:int}


float, long diferentes tipos.

length, maxlength, Garante que uma {razaoSocial:maxlength(100)}


minlength determinada string tenha
um tamanho especfico.

max, min, range Opes para determinar {idade:range(18, 65)}


intervalos.

regex Assegura que o {email:( \b[A-Z0-9._%-]+@[A-


parmetro se encaixe em Z0-9.-]+\.[A-Z]{2,4}\b)}
uma expresso regular.

Nada impede definirmos mais que uma constraint para um mesmo parmetro. Para isso
basta utilizarmos uma vrgula para separar as constraints que desejamos aplicar a este
parmetro.

[HttpGet("artistas/detalhes/{artistaId:int}")]
public Artista RecuperarDetalhes(int artistaId) { }

40
Nomenclatura das Rotas

Tanto para as rotas que definimos em nvel centralizado quanto estar em nvel de
mtodo (ao), podemos opcionalmente definir um nome que a identifique. A finalidade
deste nome facilitar a gerao dos links para recursos especficos que j existem ou
que so criados sob demanda, evitando assim a definio em hard-code de links, o que
dificulta a manuteno futura.

Como facilitador para a gerao destes links, temos uma classe chamada UrlHelper, que
utiliza a tabela de roteamento para compor as URLs necessrias para a API. A classe
ApiController possui uma propriedade chamada Url, que retorna a instncia da classe
UrlHelper j configurada para a utilizao.

[RoutePrefix("artistas")]
public class ArtistasController : ApiController
{
private static IList<Artista> artistas = new List<Artista>();
private static int Ids = 0;

[HttpPost("adicionar")]
public HttpResponseMessage AdicionarArtista(HttpRequestMessage request)
{
var novoArtista = request.Content.ReadAsAsync<Artista>().Result;
novoArtista.Id = ++Ids;
artistas.Add(novoArtista);

var resposta = new HttpResponseMessage(HttpStatusCode.Created);


resposta.Headers.Location =
new Uri(Url.Link("Detalhamento", new { artistaId = novoArtista.Id }));

return resposta;
}

[HttpGet("detalhes/{artistaId:int}", RouteName = "Detalhamento")]


public Artista BuscarDetalhes(int artistaId)
{
return artistas.SingleOrDefault(a => a.Id == artistaId);
}
}

Ao incluir o novo artista na coleo, o mtodo cria e retorna um objeto do tipo


HttpResponseMessage, definindo o header Location com o endereo para detalhar a
entidade que foi recentemente criada. O mtodo Link da classe UrlHelper j combina o
endereo geral (host) da API com o path at a ao que especificada, retornando assim
o endereo absoluto para um determinado local. O resultado da resposta mostrado
abaixo:

HTTP/1.1 201 Created


Location: http://localhost:49170/artistas/detalhes/1
Date: Mon, 01 Jul 2013 23:32:58 GMT
Content-Length: 0

41
Hosting
At o momento vimos algumas caractersticas do HTTP, a estrutura que uma API deve
ter quando utilizamos o ASP.NET Web API, a configurao para rotear as requisies
para um tratador (mtodo), etc. Mas para dar vida a tudo isso, precisamos de algum
elemento que faa com que toda essa estrutura seja ativada e, consequentemente,
passe a tratar as requisies.

O responsvel por isso o hosting. Dado todas as configuraes necessrias a ele, ele
ser responsvel por construtir toda a infraestrutura para receber, manipular, processar
e devolver a resposta ao cliente.

Ns temos algumas opes para realizar a hospedagem de APIs dentro do .NET, uma
cada uma delas possuem suas vantagens e desvantagens. As opes so: self-hosting,
web-hosting e cloud-hosting.

A primeira opo, self-hosting, consiste em hospedar as APIs em um processo que no


seja o IIS como habitualmente . Isso permitir utilizar algum outro processo do
Windows, como por exemplo, uma aplicao Console, um Windows Service, ou at
mesmo um projeto de testes, que poderemos utilizar para a facilitar a criao de testes
unitrios.

O primeiro passo para ter acesso a todos os recursos para hospedar APIs escritar em
ASP.NET Web API em um processo prprio, instalar o pacote disponvel via Nuget
chamado Microsoft ASP.NET Web API Self Host.

Figura 11 - Pacote para self-hosting.

Quando estamos falando em self-hosting, somos obrigados a criar toda a estrutura


necessria para hospedar a API, e alm disso, precisamos gerenciar a vida destes
objetos, pois eles no so ativados sob demanda, obrigando eles estarem disponveis no
momento em que a requisio chegar, caso contrrio, ela ser rejeitada.

42
Ao referenciar o pacote que vimos acima, o principal assembly que temos o
System.Web.Http.SelfHost .dll. A principal classe a ser utilizada a HttpSelfHostServer,
que em seu construtor recebe a instncia da classe HttpSelfHostConfiguration, que tem
a funo de receber todas as configuraes necessrias, para que em tempo de
execuo, fornea todos os recursos necessrios para a API ser executada.

Antes de qualquer coisa, precisamos criar a classe que representar a API, e isso no
muda em nada, independente de como hospedamos a API. Sendo assim, temos que criar
uma classe, sufixada com a palavra Controller e herdar da classe abstrata ApiController,
e a implementao dos mtodos nada muda em relao ao que j conhecemos nos
captulos anteriores.

A partir das APIs criadas, o momento de fazermos as configuraes e,


consequentemente, ceder essas informaes para que a infraestrutura consiga fazer o
papel dela. Como sabemos, as rotas tem um papel extremamente importante para
busca pela API, pelo mtodo e mapeamento dos respectivos parmetros. Todas as
configuraes, incluindo a tabela de roteamento, est acessvel a partida classe
HttpSelfHostConfiguration.

Depois das configuraes realizadas, passamos a instncia desta classe para o construtor
da classe HttpSelfHostServer. Internamente esta classe utiliza alguns recursos do
framework do WCF para extrair as mensagens do HTTP, materializando em classes para
que o ASP.NET Web API possa comear a manipular.

static void Main(string[] args)


{
var config = new HttpSelfHostConfiguration("http://localhost:9393");
config.Routes.MapHttpRoute("Default", "api/{controller}");

using (var server = new HttpSelfHostServer(config))


{
server.OpenAsync().Wait();
Console.ReadLine();
}
}

O mtodo OpenAsync, como j suspeita-se, ele tem o sufixo Async por se tratar de um
mtodo que executado de forma assncrona, retornando um objeto do tipo Task, que
representa a inicializao e abertura do servio, que quando concluda, passar a
receber as requisies. O mtodo Wait, exposto atravs da classe Task, bloqueia a
execuo at que o host seja aberto.

Um dos overloads do construtor da classe HttpSelfHostServer recebe como parmetro


uma instncia da classe HttpMessageHandler, qual podemos utilizar para interceptar a
requisio e a resposta, injetando algum cdigo customizado, como por exemplo,
efetuar o log das mensagens, inspecionar os headers, etc. No captulo sobre
estensibilidade ser abordado as opes disponveis que temos para isso.

Como vimos, a opo do self-hosting d a chance de hospedar a API em um projeto que


no seja ASP.NET e, consequentemente, no temos a necessidade termos

43
obrigatoriamente o IIS (Internet Information Services), tendo um controle mais refinido
sobre a criao e gerenciamento dos componentes da aplicao.

A outra opo que temos para hospedar APIs Web justamente utilizar o IIS (web-
hosting), que por sua vez, nos d uma infinidade de recursos para gerenciamento das
APIs, reciclagem de processo, controle de acesso, ativao, segurana, etc. Esse modelo
reutiliza a infraestrutura criada para o ASP.NET e tambm para o ASP.NET MVC para
executar os servios que sero hospedados ali.

Ao contrrio do que vimos na outra opo de hospedagem, quando optamos pelo


ASP.NET, que j temos uma template de projeto disponvel chamada Web API (mais
detalhes acima), que j traz algumas coisas j pr-configuradas, e os objetos que
utilizamos para realizar as configuraes e customizaes, j esto mais acessveis. Caso
voc j esteja utilizando outra template de projeto, podemos recorrer um outro pacote
(via Nuget) chamado Microsoft ASPNET Web API Web Host.

Figura 12 - Pacote para web-hosting.

A configurao j est acessvel atravs do arquivo Global.asax, que nos permite


interceptar alguns eventos em nvel de aplicao, e um deles o Application_Start, onde
podemos realizar todas as configuraes referente ao roteamento para assim
possibilitar os clientes chegarem at eles.

Essa configurao inicial j foi abordada nos captulos anteriores, mas claro que o
objeto de configurao (tanto no self-hosting quanto no web-hosting) so utilizados
apenas para armazenar a tabela de roteamento. Ele vai muito alm disso, e vamos
explorar mais algumas funcionalidades que ele expe nos prximos captulos.

A terceira e ltima opo abordada aqui cloud-hosting, onde estaremos utilizando o


Windows Azure para publicar e rodar as nossas APIs. Hospedar o servio na nuvem pode
facilitar o escalonamento do mesmo sem que haja a necessidade realizar mudanas na
infraestrutura, afinal, o prprio mecanismo de gerenciamento e execuo possui

44
algoritmos que detectam o alto volume de acesso e, consequemente, sugerem e/ou
ativam novas instncias (mquinas virtuais) para conseguir atender toda a demanda.

importante dizer que o hosting nada tem a ver com o meio em que a API ou qualquer
tipo de aplicao distribuda (deployment). A distribuio determina como ela
empacotada, disponibilizada e instalada no computador onde ela ser executada. Para
cada tipo de hosting que vimos at aqui, h um mecanismo de distribuio diferente,
combinando o Visual Studio para a criao do pacote e tecnologias que existem nos
computadores e servidores para a instao do mesmo.

45
Consumo
Depois da API construda, hospedada e rodando no servidor, chega o momento de
consumirmos isso do lado do cliente. Como o foco o HTTP, que bastante popular, a
grande maioria das tecnologias cliente do suporte ao consumo deste tipo de servios.
aqui que servios REST diferem bastante do SOAP. O SOAP define uma estrutura para
comunicao, que sem um ferramental que ajude, o consumo se torna bastante
complexo, uma vez que temos que manualmente formatar as mensagens de envio e
interpretar as mensagens de retorno.

Mesmo com poucos facilitadores para consumir servios por parte de uma tecnologia,
o trabalho com servios HTTP no muito complexo. Com um objeto que gerencie a
conexo, a configurao da requisio e leitura da resposta acabo sendo uma tarefa bem
mais simples do que quando comparado ao SOAP.

Podemos ter os mais variados tipos de clientes, podendo ser aplicaes desktops, de
linha de comando, aplicaes para internet, dispositivos mveis ou at mesmo outros
servios. Quando o consumo realizado por aplicaes Web, muito comum
utilizarmos cdigo script para isso, onde recorremos Javascript para solicitar o envio,
recuperar a resposta e apresentar o resultado na tela. Neste ambiente temos uma
biblioteca chamada jQuery, que fornece uma infinidade de facilitadores para o consumo
de servios REST.

Alm disso, podemos consumir servios REST em aplicaes que no so Web. Da


mesma forma que a Microsoft criou tudo o que vimos at o momento para a construo
de servios, ela tambm se preocupou em criar recursos para tornar o consumo de
servios REST em aplicaes .NET muito simples.

Para consumirmos servios REST em aplicaes .NET, o primeiro passo referenciar o


assembly System.Net.Http.dll. Dentro deste assembly temos o namespace
System.Net.Http, que possui tipos para consumir servios baseados exclusivamente no
protocolo HTTP. Os componentes que veremos aqui podem tambm ser utilizados pelo
lado do servio (como o caso das classes HttpRequestMessage e
HttpResponseMessage), fornecendo uma certo simetria entre o cdigo do lado do
cliente e do lado do servio, obviamente quando ambos forem .NET.

S que este assembly apenas no o suficiente. Ao invs de descobrirmos quais os


assemblies e recursos que precisamos, podemos recorrer ao Nuget para que ele registre
tudo o que precisamos nas aplicaes cliente para consumir servios HTTP utilizando o
ASP.NET Web API. Para isso podemos digitar a chave Microsoft.AspNet.WebApi.Client,
e j teremos a Microsoft ASP.NET Web API Client Libraries listada nos resultados, e
clicando no boto Install, elas so configuradas no projeto em questo.

importante dizer que tambm temos a verso portvel destas bibliotecas. Com isso,
poderemos reutilizar o consumo de APIs REST (HTTP) atravs de diferentes plataformas,
sem a necessidade de reconstruir a cada novo projeto uma ponte de comunicao com

46
estes tipos de servios, e ainda, sem a necessidade de recorrer de classes de mais baixo
nvel para atingir o mesmo objetivo.

Figura 13 - Pacote com recursos para consumo de APIs.

Do lado do cliente a principal classe a HttpClient. Ela responsvel por gerenciar toda
a comunicao com um determinado servio. Ela atua como sendo uma espcie de
sesso, onde voc pode realizar diversas configuraes e que sero aplicadas para todas
as requisies que partirem da instncia desta classe.

Essa a principal classe que utilizada quando estamos falando de um cliente .NET,
fornecendo mtodos nomeados com os principais verbos do HTTP, e que trabalham com
as classes HttpRequestMessage e HttpResponseMessage, o que dar ao cliente o
controle total da mensagem que enviada e da resposta que retornada. Internamente
a classe HttpClient trabalha com classes que so velhas conhecidas de quem j trabalha
com .NET: HttpWebRequest e HttpWebResponse, mas como todo e qualquer facilitador,
a classe HttpClient encapsula toda a complexidade destas classes, expondo mtodos
mais simples para consumo dos servios.

Apesar da classe HttpClient ser comparada com um proxy de um servio WCF, voc no
est obrigado a somente invocar APIs que esto debaixo de um mesmo servidor, pois
isso deve ser definido o endereo (URL) onde est localizado o servio. Caso quisermos
criar um cliente especfico para um determinado servio, podemos herdar da classe
HttpClient, e fornecer mtodos especficos para acessar os recursos que so
manipulados pela API. Um exemplo disso seria ter uma classe chamada FacebookClient,
que internamente recorrer aos mtodos da classe HttpClient encapsulando ainda mais
a pouca complexidade que temos, tornando o consumo um pouco amigvel.

Antes de analisarmos algum cdigo, importante dizer que a classe HttpClient expe os
mtodos para consumo dos servios de forma assncrona. Como o consumo depende de
recursos de I/O, os mtodos foram desenhados para que ao consumir qualquer recurso
remoto, essa tarefa seja executada por uma outra thread. E, como ele j faz uso do novo

47
mecanismo de programao assncrona do .NET (Tasks), ficar bastante simples gerenciar
e coordenar requisies que so realizadas.

class Program
{
private const string Endereco = "http://localhost:43139/api/artistas/MaxPezzali";

static void Main(string[] args)


{
Executar();
Console.ReadLine();
}

private async static void Executar()


{
using (var client = new HttpClient())
{
using (var request = await client.GetAsync(Endereco))
{
request.EnsureSuccessStatusCode();

await request.Content.ReadAsAsync<JObject>().ContinueWith(t =>


{
Console.WriteLine(t.Result["Nome"]);
});
}
}
}
}

Dentro do mtodo Executar criamos a instncia da classe HttpClient, que atravs do


mtodo GetAsync, realiza uma requisio atravs do verbo GET para o servio de
artistas, que estamos utilizando para os exemplos. Temos que fazer uso das palavras
async e await para que o C# possa criar o mecanismo necessrio para que o servio seja
invocada de forma assncrona.

O mtodo EnsureSuccessStatusCode assegura que o servio foi invocado com sucesso,


disparando uma exceo se o cdigo do status de retorno caracterizar uma falha.
Finalmente chamando o mtodo, tambm de forma assncrona, ReadAsAsync<T>. Este
mtodo realiza a leitura do corpo da mensagem de retorno, tentando converter a
mesma no tipo genrico T. No exemplo acima estamos utilizando a classe JObject, que
fornecida pelo framework Json.NET, que o mais popular meio para manipular a
serializao de objetos em Json dentro do .NET. Para instalarmos, basta recorrer ao
comando abaixo no Nuget:

PM> Install-Package Newtonsoft.Json

Finalmente, quando finalizamos a leitura do corpo da mensagem, entregamos o objeto


JObject ao ContinueWith para que ele exiba na tela. O objeto JObject implementa a
interface IDictionary, que dado uma string com o nome da propriedade, ele retorna o
seu valor.

O problema da tcnica acima que ela baseada em strings e objects, sem qualquer
tipificao, o que pode gerar erros, e que na maioria das vezes, acontecem somente

48
durante a execuo. Para facilitar isso, o Visual Studio .NET 2012, fornece dois recursos
chamados Paste JSON as Classes e Paste XML as Classes, que dado um contedo
Json ou Xml que est na rea de transferncia, ele consegue construir as classes no
projeto, configurando suas propriedades e seus respectivos tipos.

Figura 14 -Opes do Visual Studio.

public class Rootobject


{
public int Id { get; set; }
public string Nome { get; set; }
public int AnoDeNascimento { get; set; }
public int QuantidadeDeAlbuns { get; set; }
}

Desta forma, podemos passar a utilizar as classes especficas ao invs de ficar lidando
com ndices e nome das propriedades, que acaba sendo sujeito a erros. O cdigo abaixo
exibe um trecho do consumo do servio recorrendo a classe que acabamos de construir:

await request.Content.ReadAsAsync<Artista>().ContinueWith(t =>


{
Console.WriteLine(t.Result.Nome);
});

Como pudemos perceber, o mtodo GetAsync recebe apenas o endereo para onde a
requisio deve ser realizada. Mas e se quisermos customizar a requisio? Por exemplo,
incluir headers especficos para caching e segurana, especificar o formato de resultado
que desejamos, etc. Devido a essas necessidades que devemos recorrer a construo
e configurao da classe HttpRequestMessage. atravs dela que toda a configurao
realizada antes da mesma partir para o servio, e depois que ela estiver devidamente
configurada, recorremos ao mtodo SendAsync, que como parmetro recebe a classe
HttpRequestMessage e retorna a classe HttpResponseMessage. Apesar de Send no
refletir um verbo do HTTP, dentro da mensagem que vamos especificar qual verbo
ser utilizado para realizar a requisio.

49
Utilizando o mesmo exemplo acima, vamos customizar a requisio para que ela retorne
o artista em formato Xml:

using (var client = new HttpClient())


{
using (var request = new HttpRequestMessage(HttpMethod.Get, Endereco))
{
request.Headers.Add("Accept", "application/xml");

using (var response = await client.SendAsync(request))


Console.WriteLine(response.Content.ReadAsStringAsync().Result);
}
}

A classe HttpMethod traz algumas propriedades estticas com os principais verbos


criados, prontos para serem utilizados. Logo na sequncia estamos adicionando um
novo header chamado Accept, que determina o formato que queremos que o retorno
seja devolvido. Da mesma forma que podemos utilizar a classe HttpRequestMessage
para customizar a requisio, podemos inspecionar a classe HttpResponseMessage para
explorarmos tudo aquilo que o servio nos devolveu e, consequentemente, tomar
decises, realizar logs, novas requisies, etc.

Tanto a classe HttpRequestMessage quanto a HttpResponseMessage implementam a


interface IDisposable, e por isso, podem ser envolvidas em blocos using. Ambas as
classes fornecem uma propriedade chamada Content, onde temos o corpo das
mensagens, e como ele pode ser um stream, a implementao dessa interface auxilia no
descarte imediato quando elas no esto mais sendo utilizadas.

Quando vamos utilizar um verbo diferente do GET, como o caso do POST, ento
precisamos definir o corpo da mensagem de envio, onde temos vrias opes para os
mais diversos contedos que enviamos para o servidor. O diagrama abaixo d uma
dimenso disso.

50
Figura 15 - Hierarquia das classes que representam o contedo das mensagens.

Cada uma dessa classes lidam exclusivamente com um tipo de contedo. Temos como
customizar o envio determinando que o corpo deve ser uma espcie de formulrio,
string, stream e objetos.

Independente se estamos falando de requisio ou resposta, a classe ObjectContent<T>


tem a funo de materializar objetos, baseando-se no formato que ele foi serializado.
Existem classes que representam esses formatos, quais falaremos delas mais adiante,
mas quando estamos consumindo o servio atravs desta biblioteca, no precisamos
lidar diretamente com elas, pois existem alguns facilitadores que abstraem essa
complexidade, e os formatadores apenas faro o trabalho (bidirecional) sobre os bytes,
o que de fato o que trafega entre as partes.

private const string Endereco = "http://localhost:43139/api/artistas/Adicionar";

private async static void Executar()


{
using (var client = new HttpClient())
{
await client.PostAsync(Endereco, new ObjectContent<Artista>(new Artista()
{
Nome = "PaoloMeneguzzi"
}, new JsonMediaTypeFormatter())).ContinueWith(t =>
{
Console.WriteLine(t.Result.StatusCode);
});
}
}

No exemplo que temos acima, estamos recorrendo ao mtodo PostAsync, para que o
objeto (classe Artista) seja postado. Neste caso, temos que explicitamente mencionar
que queremos que o contedo seja serializado atravs de Json. Felizmente, graas

51
algumas extenses que j temos no ASP.NET Web API, podemos tornar esse cdigo
menos verboso:

private const string Endereco = "http://localhost:43139/api/artistas/Adicionar";

private async static void Executar()


{
using (var client = new HttpClient())
{
await client.PostAsJsonAsync(Endereco,
new Artista() { Nome = "PaoloMeneguzzi" }).ContinueWith(t =>
{
Console.WriteLine(t.Result.StatusCode);
});
}
}

Da mesma forma que temos do lado do servio, a classe HttpClient tambm possui um
overload do construtor que recebe a instncia de uma classe do tipo
HttpMessageHandler, qual podemos utilizar para interceptar a requisio e a resposta,
injetando algum cdigo customizado, como por exemplo, efetuar o log das mensagens,
inspecionar os headers, etc. No captulo sobre estensibilidade ser abordado as opes
disponveis que temos para isso.

52
Formatadores
Um dos maiores benefcios ao se utilizar uma biblioteca ou um framework a facilidade
que ele nos d para tornar a construo de algo mais simplificada, abstraindo alguns
pontos complexos, permitindo com que o utilizador foque diretamente (e na maioria
das vezes) na resoluo de problemas voltados ao negcio, sem gastar muito tempo
com questes inerentes infraestrutura e/ou similares.

A finalidade do ASP.NET Web API justamente facilitar a construo de APIs para expor
via HTTP. Apesar de uma das principais caractersticas de uma API abraar o HTTP, a
abstrao acaba sendo til em alguns casos, mas em outros no. A Microsoft se
preocupou com isso, abstraindo alguns aspectos para tornar a construo e o consumo
destas APIs mais fceis, sem perder o poder de customizao e acesso aos recursos
expostos pelo protocolo HTTP.

Como vimos nos captulos anteriores, possumos os objetos HttpRequestMessage e


HttpResponseMessage, quais podemos definir na assinatura das aes do controller e,
consequentemente, ter o acesso total todos os recursos do HTTP. Apesar de que em
alguns casos isso possa ser til, na sua grande maioria, temos que lidar com alguns
pontos que a abstrao poderia ajudar a nos manter mais focados no negcio do que na
infraestrutura.

Um grande exemplo disso tudo o contedo (payload) da mensagem. Em geral, o corpo


da mensagem representa um objeto que deve ser materializado e entregue ao mtodo
que tratar a requisio. A postagem que o cliente faz ao servio pode ser realizada em
diferentes formatos, como por exemplo: Json, Xml, Csv, formulrio, etc.

Como j foi dito anteriormente, o uso de um framework tem a finalidade de abstrair


certos pontos para tornar a programao mais simples. Aqui temos um grande exemplo
disso. O ASP.NET Web API fornece alguns recursos intrinscos que torna a serializao e
deserializao transparente ao ponto de vista do servio/mtodo. Esses recursos so o
Model Binding e os Formatadores.

As aplicaes geralmente trabalham com objetos que descrevem suas caractersticas,


onde estes objetos so manipulados o tempo todo, j que na grande maioria dos casos,
ela acaba tambm sendo persistido no banco de dados, apresentado na tela, etc. Como
esses objetos so parte do core da aplicao, muito comum criarmos formulrios que
apresente a instncia no mesmo na tela (HTML), para que o usurio seja capaz de edit-
lo.

Ao submeter o formulrio para o servidor, todas as informaes (querystrings, body,


URI, etc.) chegam atravs de um dicionrio, onde cada valor est associado uma chave.
Ao invs de manualmente construirmos a instncia da classe baseada no corpo da
requisio, o ASP.NET MVC j fez esse rduo trabalho para ns, e o responsvel por isso
so os model binders. Baseando-se na action para qual estamos postando a requisio,
ele captura o tipo do objeto que precisa ser criado, mapeando o dicionrio para cada
uma de suas propriedades.

53
Olhando mais de perto, os model binders so os responsveis por construir os objetos,
baseando-se em um dicionrio que contm as informaes que foram extradas da
requisio atravs de Value Providers. O ASP.NET Web API possui algumas
implementaes embutidas, mas nada impede de criarmos alguma customizao tanto
para o value provider (se quisermos customizar como extrair as informaes da
requisio), bem com o model binder (se quisermos customizar como construir a
instncia do objeto).

Ao efetuar uma requisio para algum recurso sobre o protocolo HTTP, o servidor
identifica o mesmo, faz o processamento, gera o resultado e, finalmente, devolve o
resultado para o cliente que fez a solicitao. Por mais que isso no fica explcito, o
contedo que trafega do cliente para o servidor (requisio) e do servidor para o cliente
(resposta), sempre possui um formato especfico.

Em grande parte de todos os recursos fornecidos atravs do protocolo HTTP, uma das
necessidades justamente definir o formato deste contedo, que por sua vez, direciona
a interpretao pelo navegador, por uma outra aplicao ou at mesmo de uma
biblioteca, permitindo efetuar o parser do resultado e, consequentemente, materializar
o mesmo em algo "palpvel"/visvel.

Os formatos so representados por uma simples string, onde voc tem uma primeira
parte para descrever qual o tipo de contedo, e depois o seu formato. Por exemplo, ao
invocar uma pgina onde o retorno um contedo HTML, o formato ser definido como
text/html; ao solicitar uma imagem, o seu formato ser definido como image/jpeg. Uma
lista contendo todos os formatos de contedos disponveis na internet, gerenciada e
mantida por entidade chamada IANA.

Como o ASP.NET Web API tem uma forte afinidade com as caractersticas do HTTP, ele
permite receber ou gerar contedos em formatos popularmente conhecidos pelo
mercado, e vamos perceber que os servios que criamos utilizando essa API nada sabem
sobre o formato em que ele chegou ou o formato em que ele ser devolvido para o
cliente. O ASP.NET Web API unifica o processo de serializao e deserializao dos
modelos atravs de formatadores, que baseado em um media type especfico, executa
o trabalho para materializar a requisio em um objeto de negcio (modelo).

Apesar dos principais formatadores j estarem vinculados execuo, precisamos


analisar a estrutura da classe que representa um media type para realizar futuras
customizaes. Para isso, a Microsoft criou uma classe abstrata chamada de
MediaTypeFormatter, e j existem algumas implementaes definidas dentro da API,
como por exemplo, as classes XmlMediaTypeFormatter e JsonMediaTypeFormatter.

Uma pergunta pertinente que aparece como o ASP.NET Web API escolhe qual dos
formatadores utilizar. A escolha se baseia no formato solicitado pelo cliente. O formato
pode ser includo como um item na requisio, atravs do header Accept ou do Content-
Type. O ASP.NET Web API escolhe o formatador de acordo com o valor que ele encontra
em um desses headers, e caso o formato definido no for encontrado, o padro
sempre devolver o contedo em formato Json.

54
Figura 16 - Hierarquia das classes de formatadores.

Ao contrrio do que fazemos no cliente, o servio no trabalha diretamente com estes


formatadores, pois isso fica sob responsabilidade de objetos internos, que durante a
execuo fazem todo o trabalho para encontrar para ler ou escrever o contedo no
formato requisitado. O responsvel por fazer esta anlise e encontrar o formatador
adequado a classe DefaultContentNegotiator atravs do mtodo Negotiate (fornecido
pela interface IContentNegotiator).

Para percebermos a mgica que o ASP.NET Web API faz, vamos utilizar o Fiddler para
criar e monitorar as requisies. No primeiro exemplo, vamos invocar um mtodo que
dado o nome do artista, ele retorna um objeto complexo contendo as caractersticas
deste artista. Abaixo temos a primeira requisio sendo executada e seu respectivo
retorno.

[Requisio]

GET http://localhost:43139/api/artistas?nome=MaxPezzali HTTP/1.1


User-Agent: Fiddler
Host: localhost:43139

[Resposta]

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 75

55
{"Id":5,"Nome":"MaxPezzali","AnoDeNascimento":1967,"QuantidadeDeAlbuns":20}

Note que no mencionamos nenhum header extra na requisio, e o objeto artista foi
devolvido serializado em Json. Ns podemos requisitar que o contedo seja devolvido
em um determinado padro. Para isso, recorreremos ao atributo Accept para informar
ao servio que o aceito o retorno em um determinado formato. Os logs abaixo exibem
a requisio e a resposta para o formato Xml:

[Requisio]

GET http://localhost:43139/api/artistas?nome=MaxPezzali HTTP/1.1


Host: localhost:43139
Accept: application/xml

[Resposta]

HTTP/1.1 200 OK
Content-Type: application/xml; charset=utf-8
Content-Length: 252

<Artista xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://schemas.datacontract.org/2004/07/MusicStore.Models"><AnoDeNasci
mento>1967</AnoDeNascimento><Id>0</Id><Nome>MaxPezzali</Nome><Quantidad
eDeAlbuns>20</QuantidadeDeAlbuns></Artista>

Percebemos que a o resultado bem maior quando o resultado devolvido em Xml,


pelo fato da sua estrutura ser bem mais verbosa que o Json. Alm disso, ainda h quem
defenda que se o servio no suportar o formato requisitado pelo cliente, ele no
deveria acatar a requisio. Para termos este comportamento no ASP.NET Web API, ns
temos que criar cdigo customizado para conseguir rejeitar a requisio.

Como vimos acima, por padro, o ASP.NET Web API faz a busca do formato na coleo
de headers da requisio, mas isso pode ser customizado. Podemos instruir o ASP.NET
Web API localizar o formato na querystring, e utilizaremos o objeto de configurao para
realizar esse ajuste.

56
Figura 17 - Hierarquia das classes referente ao mapeamento de media-types.

Existe uma classe chamada MediaTypeMapping, e como o nome sugere, ele traz a
infraestrutura para extrair o media type de algum elemento da requisio. Como vemos
no diagrama acima, temos as classes QueryStringMapping e RequestHeaderMapping,
que buscam o media type dentro da coleo de querystrings e headers,
respectivamente.

Note que no cdigo abaixo inserimos o mapeador de querystring, indicando qual a chave
onde ser informado o formato, e se ele for encontrado, o media type ser utilizado
pelos componentes internos para gerar o resultado no formato que o cliente est
solicitando em um local diferente do padro.

public class WebApiApplication : System.Web.HttpApplication


{
protected void Application_Start()
{
WebApiConfig.Register(GlobalConfiguration.Configuration);

this.ConfigMediaTypeMappings(GlobalConfiguration.Configuration);
}

private void ConfigMediaTypeMappings(HttpConfiguration config)


{
config.Formatters.JsonFormatter.MediaTypeMappings.Add(
new QueryStringMapping("formato", "json", "application/json"));

config.Formatters.JsonFormatter.MediaTypeMappings.Add(
new QueryStringMapping("formato", "xml", "application/xml"));
}
}

Com o cdigo acima em funcionamento, a requisio pode ser realizada da seguinte


forma:

http://localhost:43139/api/artistas?nome=MaxPezzali&formato=json
http://localhost:43139/api/artistas?nome=MaxPezzali&formato=xml

57
Customizao

Apesar do Xml e Json serem os principais formatos que temos atualmente, pode haver
situaes onde desejamos criar um formato prprio, para que esse possa gerar e/ou
receber o contedo em um formato especfico. Como j percebemos acima, se
desejarmos fazer isso, temos que recorrer implementao da classe abstrata
MediaTypeFormatter, customizando basicamente dois mtodos principais
OnReadFromStream e OnWriteToStream. Vamos analisar cada um desses mtodos
abaixo:

CanReadType: Dado um objeto do tipo Type, este mtodo retorna um valor


boleano (onde o padro True), indicando se aquele tipo ou no entendido
por aquele formatador. O tipo identifica os eventuais parmetros que existem
no mtodo do servio. Aqui podemos fazer validaes, como por exemplo,
identificar se o tipo ou no serializvel, se possui um determinado atributo,
etc.
ReadFromStreamAsync: Se o mtodo acima retornar True, ento este mtodo
executado. Como parmetro ele recebe o tipo do objeto (o mesmo que foi
passado para o mtodo acima), e um objeto do tipo Stream, que fonte das
informaes (estado) do objeto a ser criado. Este mtodo retorna um object, que
corresponde um objeto criado dinamicamente e configurado com os valores
provenientes do Stream.
CanWriteType: Dado um objeto do tipo Type, este mtodo retorna um valor
boleano (padro True), indicando se aquele tipo ou no entendido pelo
formatador. O tipo identifica o retorno do mtodo do servio. Aqui podemos
fazer validaes, como por exemplo, identificar se o tipo ou no serializvel, se
possui um determinado atributo, etc.
WriteToStreamAsync: Se o mtodo acima retornar True, ento este mtodo
executado. Como parmetro, ele recebe o tipo do objeto a ser serializado e um
object que corresponde a instncia do objeto a ser gravado. Ainda recebemos
um Stream, que o destino do objeto serializado.

Como um possvel exemplo, podemos criar um formatador especfico para o formato


CSV, que um padro bem tradicional, onde cada valor separado pelo caracter ";".
Abaixo temos a classe CsvMediaTypeFormatter, que herda de MediaTypeFormatter.
Note a definio do formato application/csv sendo adicionado coleo de media types
suportados por este formatador customizado, que est acessvel atravs da propriedade
SupportedMediaTypes.

public class CsvMediaTypeFormatter : MediaTypeFormatter


{
private const char SEPARATOR = ';';

public CsvMediaTypeFormatter()
{
this.SupportedMediaTypes.Add(
new MediaTypeHeaderValue("application/csv"));
}

58
//implementao
}

Como j era esperado, o que precisamos fazer a partir de agora instal-lo execuo.
E para isso, recorremos novamente a classe de configurao do ASP.NET Web API, que
atravs da propriedade Formatter (que uma coleo), podemos incluir classes que
herdam de MediaTypeFormatter. O que fazemos aqui instanciar e adicionar a classe
CsvMediaTypeFormatter:

config.Formatters.Add(new CsvMediaTypeFormatter());

Com isso, ao receber ou retornar uma mensagem com o header Accept ou Content-Type
definido como application/csv, a API j capaz de interpretar e retornar objetos
serializados neste formato.

59
Segurana
Como qualquer outro tipo de aplicao, servios tambm devem lidar com segurana. E
quando falamos em segurana sempre abordamos dois itens: autenticao e
autorizao. A autenticao o processo que consiste em saber quem o usurio , se
ele est corretamente cadastrado e configurado, enquanto a autorizao determina se
esse usurio possui permisses para acessar o recurso que ele est solicitando. A
autenticao, obrigatoriamente, sempre ocorre antes da autorizao, pois no h como
avaliar/conceder permisses sem antes saber quem ele .

E como se no bastasse isso, quando estamos lidando com aplicaes que encaminham
mensagens de um lado para outro, necessrio tambm nos preocuparmos com a
proteo da mesma enquanto ela viaja de um lado ao outro. Neste ponto o protocolo
HTTPS ajuda bastante, j que ele popularmente conhecido e a grande maioria dos
hosts e clientes sabem lidar com ele.

Antes de falar sobre as peculiaridades do ASP.NET Web API, precisamos entender alguns
conceitos de segurana que existem dentro da plataforma .NET desde a verso 1.0. Duas
interfaces so utilizadas como base para os mecanismos de autenticao e autorizao:
IIdentity e IPrincipal (namespace System.Security.Principal), respectivamente. A
interface IIdentity fornece trs propriedades autoexplicativas: Name,
AuthenticationType e IsAuthenticated. J a segunda possui dois membros que merecem
uma ateno especial. O primeiro deles a propriedade Identity que retorna a instncia
de uma classe que implemente a interface IIdentity, representando a identidade do
usurio; j o segundo membro trata-se de um mtodo chamado IsInRole que, dado uma
papel, retorna um valor boleano indicando se o usurio corrente possui ou no aquele
papel. Como podemos notar, as classes de autenticao e autorizao trabalham em
conjunto.

Dentro do namespace System.Threading existe uma classe chamada Thread. Essa classe
determina como controlar uma thread dentro da aplicao. Essa classe, entre vrios
membros, possui uma propriedade esttica chamada CurrentPrincipal que recebe e
retorna uma instncia de um objeto que implementa a interface IPrincipal. atravs
desta propriedade que devemos definir qual ser a identity e principal que ir
representar o contexto de segurana para a thread atual.

H algumas implementaes das interfaces IIdentity e IPrincipal dentro do .NET


Framework, como o caso das classes GenericIdentity, WindowsIdentity,
GenericPrincipal e WindowsPrincipal. Essas classes so utilizadas, principalmente,
quando queremos implementar no sistema o mecanismo de autorizao baseado em
papis, que dado um papel (muitas vezes um departamento), indica se o usurio pode
ou no acessar o recurso. Para refinar melhor isso, ao invs de nomearmos por
departamento, podemos definir as sees e funcionalidades do sistema que ele poder
acessar/executar.

Em qualquer tipo de projeto ASP.NET, h uma classe chamada HttpContext. Como o


prprio nome sugere, essa classe expe uma srie de recursos que estaro acessvel por

60
todo o ciclo da requisio dentro do servidor, e um desses recursos o contexto de
segurana do usurio, que atravs da propriedade User podemos ter acesso ao objeto
(IPrincipal) que define a credencial do usurio corrente. Essa propriedade tambm
estar acessvel quando hospedar a API em um modelo de web-hosting. Quando
utilizarmos o self-hosting, temos que recorrer a propriedade CurrentPrincipal da classe
Thread. Se precisarmos hospedar a API em ambos os locais, temos que definir a
credencial em ambos os locais, mas no caso do HttpContext, temos que nos certificar
que a propriedade esttica Current no seja nula, pois ela ser se estiver em modo self-
hosting.

H diversas formas de trabalhar com autenticao no ASP.NET Web API, onde a maioria
j so bastante conhecidas pelos desenvolvedores e padres j estabelecidos no
mercado. Abaixo temos as principais opes:

Basic: A autenticao Basic faz parte da especificao do protocolo HTTP, que


define um modelo simples (bsico) para transmisso de nome de usurio e senha
nas requisies. A sua simplicidade to grande quanto a sua insegurana. Por
no haver qualquer meio de proteo (hash, criptografia, etc.), obriga a sempre
trafegar essas requisies recorrendo segurana do protocolo, e para isso,
seremos obrigados a utilizarmos HTTPS.
Digest: Tambm parte da especificao do protocolo HTTP, uma modelo mais
seguro quando comparado ao Basic, pois apenas o hash da senha (MD5)
enviado ao servio.
Windows: Como o prprio nome diz, a autenticao baseada nas credenciais
do usurio que est acessando o recurso, baseando-se em uma conta no
Windows (Active Directory). Entretanto isso apenas til quando estamos
acessando a partir de uma intranet onde conseguimos ter um ambiente
controlado e homogneo.
Forms: Desenhado para a internet a autenticao baseada em forms est
presente no ASP.NET desde a sua verso 1.0, e baseada em cookies.

At ento somente foi falado sobre os tipos de autenticao, o gerenciamento da


identidade e dos objetos que temos a disposio e que representam o usurio, mas no
de como e quando configurar isso. A escolha depender de como e onde quer (re)utilizar
esse mecanismo de autenticao. Se quisermos avaliar em qualquer modelo de hosting,
ento a melhor opo recorrer ao uso de message handlers, que trata-se de um pouco
de estensibilidade do ASP.NET Web API e que pode rodar para todas as requisies ou
para um determinada rota. Haver um captulo para esgotar este assunto.

Para exemplificar vamos nos basear na autenticao Basic. A ideia criar um handler
para interceptar a requisio e extrair o header do HTTP que representa a credencial
informada pelo usurio (WWW-Authenticate), e a valida em algum repositrio de sua
escolha, como uma base de dados. A partir daqui necessrio conhecermos como
funciona o processo deste modelo, para conseguirmos dialogar com o cliente, para que
assim ele consiga coordenar o processo de autenticao do usurio.

61
O cliente solicita um recurso (pgina, servio, etc.) que est protegido.
Ao detectar que o cliente no est autenticado, o servidor exige que ele se
autentique e informe as credenciais a partir do modelo Basic. Isso informado a
partir de um header chamado WWW-Authenticate: Basic.
Neste momento, o servidor retorna uma resposta com o cdigo 401
(Unauthorized), que instrui o cliente (navegador) a exigir as credenciais de acesso
do usurio que est acessando o recurso.
Uma vez informado, o browser recria a mesma requisio, mas agora envia nos
headers da mesma o login e senha codificados em Base64, sem qualquer espcie
de criptografia. Na resposta, o header enviado o Authorization: Basic
[Username+Password Codificado].
Quando este header acima estiver presente, o servidor (IIS) capaz de valid-lo
no Windows/Active Directory, e se for um usurio vlido, permitir o acesso, caso
contrrio retornar a mesma resposta com cdigo 401, at que ele digite uma
credencial vlida.

Como dito acima, o login e a senha no so enviados at que sejam efetivamente


exigidos. Nesta customizao, ao identificarmos que o header no est presente na
requisio, precisamos configurar a resposta para o cliente com o cdigo 401, que
representa acesso no autorizado, e informar na resposta o mesmo header, para
continuar obrigando o usurio a informar o login e senha.

Para saber se o cliente informou as credenciais, precisamos detectar a presena do


header chamado Authorization. Se existir, ento precisamos decodific-lo, utilizando o
mtodo FromBase64String da classe Convert, que dado uma string, retorna um array de
bytes representando as credenciais separadas por um ":". Depois disso, tudo o que
precisamos fazer separ-los, para que assim podermos efetuar a validao em algum
repositrio.

Depois de conhecer um pouco mais sobre o processo que ocorre entre cliente e servio,
vamos implementar isso no ASP.NET Web API utilizando um message handler, que a
forma que temos para interceptar as requisies que chegam para a API.

public class AuthenticationHandler : DelegatingHandler


{
protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
string username = null;

if (IsValid(request, out username))


{
var principal = new GenericPrincipal(new GenericIdentity(username), null);
Thread.CurrentPrincipal = principal;

if (HttpContext.Current != null)
HttpContext.Current.User = principal;

return base.SendAsync(request, cancellationToken);


}
else
{
return Task.Factory.StartNew(() =>
{

62
var r = new HttpResponseMessage(HttpStatusCode.Unauthorized);
r.Headers.Add("WWW-Authenticate", "Basic realm=\"AppTeste\"");
return r;
});
}
}
}

Ao recepcionar a requisio e ela for vlida, antes dele encaminhar a mesma adiante,
para que ela chegue at a ao que o cliente requisitou, ele cria o objeto que definir a
credencial/identidade do usurio que est acessando o recurso. Ao requisitar pela
primeira vez e se estivermos consumindo isso em um navegador, ao receber esse cdigo
em conjunto com este header, uma janela aberta para que voc informe o login e
senha, que sero encaminhados ao servio.

Figura 18 - Solicitao de login e senha pelo browser.

Ao interceptar essa requisio, podemos comprovar tudo o que foi escrito acima. Temos
a resposta contendo o cdigo 401, e depois de informado o login e senha, a nova
requisio com o header Authorization contendo o valor codificado em Base64.

Figura 19 - Headers referente autenticao Basic.

63
private static bool IsValid(HttpRequestMessage request, out string username)
{
username = null;
var header = request.Headers.Authorization;

if (header != null && header.Scheme == "Basic")


{
var credentials = header.Parameter;

if (!string.IsNullOrWhiteSpace(credentials))
{
var decodedCredentials =
Encoding.Default.GetString(Convert.FromBase64String(credentials));

var separator = decodedCredentials.IndexOf(':');


var password = decodedCredentials.Substring(separator + 1);

username = decodedCredentials.Substring(0, separator);

return username == password; //Validao em algum repositrio


}
}

return false;
}

A classe ApiController fornece uma propriedade chamada User, que retorna um objeto
do tipo IPrincipal. Isso quer dizer que, se precisar extrair as credenciais do usurio dentro
do mtodo/ao, podemos recorrer a ela. E, para finalizar, necessrio incluir este
handler na coleo de handlers do servio, atravs do arquivo Global.asax:

config.MessageHandlers.Add(new AuthenticationHandler());

Depois da autenticao finalizada, de sabermos quem o usurio que est acessando o


recurso, chega o momento de controlarmos e sabermos e se ele tem as devidas
permisses para acesso, que o processo de autorizao.

O principal elemento que controla o acesso o atributo AuthorizeAttribute (namespace


System.Web.Http), e pode ser aplicado em um controller inteiro ou individualmente em
cada ao, caso precisemos de um controle mais refinado, ou at mesmo, em nvel
global, onde ele deve ser executado/assegurado independente de qualquer controller
ou ao que seja executada dentro daquela aplicao. Este atributo possui duas
propriedades: Roles e Users. Cada uma delas recebe um string com o nome dos papis
ou usurios que podem acessar determinado recurso, separados por vrgula.

Pelo fato deste atributo ser um filtro (falaremos mais sobre eles abaixo), ele executado
diretamente pela infraestrutura do ASP.NET Web API, que ir assegurar que o usurio
est acessando est dentro daqueles nomes colocados na propriedade Users ou que ele
esteja contido em algum dos papis que so colocados na propriedade Roles. E como j
era de se esperar, ele extrai as informaes do usurio da propriedade CurrentPrincipal
da classe Thread, qual definimos durante o processo de autenticao, dentro do mtodo
SendAsync do handler criado acima.

64
Depois de saber quem o usurio , podemos extrair as permisses que ele possui, que
provavelmente estaro armazenadas em algum repositrio tambm. No exemplo que
vimos acima da autenticao, h um segundo parmetro na classe GenericPrincipal que
um array de strings, que representam os papis do usurio. Abaixo temos aquele
mesmo cdigo ligeiramente alterado para buscar pelas permisses do usurio:

var principal =
new GenericPrincipal(
new GenericIdentity(username),
CarregarPermissoes(username));

//....

private static string[] CarregarPermissoes(string username)


{
if (username == "Israel")
return new[] { "Admin", "IT" };

return new[] { "Normal" };


}

Como comentado acima, temos trs nveis que podemos aplicar o atributo
AuthorizeAttribute: no mtodo, no controller e em nvel global. O cdigo abaixo ilustra
o uso destas trs formas de utilizao:

//Nvel de Mtodo
public class ClientesController : ApiController
{
[Authorize(Roles = "Admin, IT")]
public IEnumerable<Cliente> Get()
{
//...
}
}

//Nvel de Controller
[Authorize(Roles = "Admin")]
public class ClientesController : ApiController
{
public IEnumerable<Cliente> Get()
{
//...
}
}

//Nvel Global
config.Filters.Add(new AuthorizeAttribute());

E se quisermos refinar ainda mais a autorizao, podemos levar a validao disso para
dentro do mtodo. Basta remover o atributo e recorrer ao mtodo IsInRole atravs da
propriedade User, que dado o nome do papel, retorna um valor boleano indicando se o
usurio atual est ou no contido nele.

public IEnumerable<Cliente> Get()


{
if (User.IsInRole("Admin"))
//Retornar todos os clientes.

65
//Retornar apenas os clientes da carteira
}

Somente o fato de utilizar o atributo AuthorizeAttribute aplicado em alguns dos nveis


que vimos, o suficiente para que o ASP.NET Web API consiga assegurar que ele
somente aquele determinado mtodo/controller se ele estiver autenticado,
independente dos papis que ele possua. Se quisermos flexibilizar o acesso alguns
mtodos, podemos recorrer ao atributo AllowAnonymousAttribute para conceder o
acesso um determinado mtodo, mesmo que o controller esteja marcado com o
atributo AuthorizeAttribute.

66
Testes e Tracing
importante testarmos a maioria dos cdigos que escrevemos, e quando estamos
falando em testes, no estamos necessariamente nos referindo sobre testes de alto
nvel, onde colocamos o usurio para realizar os testes. Nos referimos a testes
automatizados, onde conseguimos escrever cdigos para testar cdigos, possibilitando
a criao de diversos cenrios para se certificar de que tudo funcione como esperado.

Como comentamos no decorrer dos captulos anteriores, o ASP.NET Web API possibilita
a construo de servios de modelo tradicional, ou seja, definir tipos que refletem o
nosso negcio (Cliente, Produto, Pedido, etc.), bem como tipos mais simples (inteiro,
string, boleano, etc.). Como sabemos, a finalidade conseguir desenhar um servio que
nada saiba sobre a infraestrutura, como ele exposto, caractersticas, etc.

Ainda temos a possibilidade de receber e/ou retonar objetos que refletem e fazem uso
de algumas informaes do protocolo HTTP, que um detalhe muito importante na
estrutura REST. Ao utilizar as classes que descrevem a requisio (HttpRequestMessage)
e a resposta (HttpResponseMessage), podemos interagir com detalhes do protocolo.

No h muito mistrio em aplicar testes em cima da classe que representa o servio


quando estamos lidando com tipos customizados. Isso se deve ao fato de que neste
modelo, como so simples classes, com mtodos que executam tarefas e,
eventualmente, retornam algum resultado, isso acaba sendo tratado como sendo uma
classe de negcio qualquer.

Mas e quando queremos receber e/ou enviar dados para este servio, utilizando
instncias das classes HttpRequestMessage e HttpResponseMessage? Felizmente, assim
como no ASP.NET MVC, a Microsoft desenvolveu o ASP.NET Web API com a
possibilidade de test-lo sem estar acoplado infraestrutura do ASP.NET, o que permite
testar a classe do servio, mesmo que ela receba ou devolva objetos caractersticos do
protocolo HTTP.

Supondo que temos um servio que possui dois mtodos (Ping e PingTipado), podemos
escrever testes e, consequentemente, utilizar a IDE do Visual Studio para execut-los, e
como isso, nos antecipamos eventuais problemas que possam acontecer, pois talvez
seja possvel capturar alguns desses problemas antes mesmo de levar o mesmo ao
ambiente de produo.

public class ServicoDeExemplo : ApiController


{
public HttpResponseMessage Ping(HttpRequestMessage request)
{
return new HttpResponseMessage()
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent(request.Content.ReadAsStringAsync().Result)
};
}

public HttpResponseMessage PingTipado(HttpRequestMessage request)


{

67
if (request.Content == null)
return request.CreateErrorResponse(HttpStatusCode.BadRequest,
new HttpError("Contedo no definido"));

return new HttpResponseMessage()


{
StatusCode = HttpStatusCode.OK,
Content =
new ObjectContent<Informacao>(
request.Content.ReadAsAsync<Informacao>().Result,
new JsonMediaTypeFormatter())
};
}
}

No primeiro exemplo, estamos testando o mtodo Ping, instanciando a classe que


representa o servio, e passando ao mtodo Ping a instncia da classe
HttpRequestMessage. Neste momento, poderamos abastecer informaes na coleo
de headers da requisio, com o intuito de fornecer tudo o que necessrio para o que
o mtodo/teste possa executar com sucesso. Depois da requisio realizada,
verificamos se o status da resposta corresponde ao status OK. Alm disso verificamos
tambm se o contedo da resposta est igual informao que enviamos.

[TestMethod]
public void DadoUmaRequisicaoSimplesDeveRetornarStatusComoOK()
{
var info = "teste";

var response = new ServicoDeExemplo().Ping(new HttpRequestMessage()


{
Content = new StringContent(info)
});

Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
Assert.AreEqual(info, response.Content.ReadAsStringAsync().Result);
}

O prximo passo construir um teste para o mtodo PingTipado. Esse mtodo recebe
como parmetro a instncia da classe HttpRequestMessage, definindo o contedo uma
instncia da classe ObjectContent<T>, onde definimos o tipo genrio T como sendo do
tipo Informacao. A finalidade do teste assegurar que, se passarmos uma instncia nula
da classe Informacao, uma resposta ser retornada definindo o cdigo de status como
400 (Bad Request).

[TestMethod]
public void DadoUmObjetoInfoNuloDeveRetornarComoErro()
{
var response =
new ServicoDeExemplo().PingTipado(new HttpRequestMessage());

Assert.AreEqual(HttpStatusCode.BadRequest, response.StatusCode);
}

Finalmente, o prximo passo consiste em criar um teste, tambm para o mtodo


PingTipado, mas agora fornecendo a instncia do objeto Informacao em um estado
vlido, para que o teste possa suceder se o servio retornar a mesma instncia da classe

68
Informacao, onde os membros da requisio reflitam o que est sendo retornado como
reposta. Abaixo o cdigo que efetua o tal teste:

[TestMethod]
public void DadoUmObjetoInfoDeveRetornarEleComInformacoesExtra()
{
var info = new Informacao() { Codigo = "123", Dado = "Alguma Info" };
var response =
new ServicoDeExemplo()
.PingTipado(new HttpRequestMessage()
{
Content =
new ObjectContent<Informacao>(info, new JsonMediaTypeFormatter())
})
.Content
.ReadAsAsync<Informacao>().Result;

Assert.AreEqual(info.Dado, response.Dado);
}

Para abstrair ainda o que est sendo testado, a Microsoft criou uma interface chamada
IHttpActionResult, que encapsula o resultado dos retornos de aes. A implementao
desta classe ser responsvel por criar a mensagem de retorno, e a ao dentro do
controller passa a retornar uma classe que implemente esta interface, facilitando os
testes unitrios. O ASP.NET j est preparado para tambm entender este tipo
resultado, processando o retorno normalmente.

J temos nativamente cinco implementaes: FormattedContentResult<T>,


NegotiatedContentResult<T>, StatusCodeResult, ContinuationResult e MessageResult.
Cada uma delas responsvel por receber um determinado tipo de resultado, prepar-
lo e repassar para o sistema de testes ou para o pipeline ASP.NET um tipo genrico, que
nada mais que a instncia da classe HttpResponseMessage.

public IHttpActionResult Get(string nome)


{
var artista =
new Artista() { Id = 12, Nome = nome };

return new FormattedContentResult<Artista>(


HttpStatusCode.OK,
artista,
new JsonMediaTypeFormatter(),
new MediaTypeHeaderValue("application/json"),
this.Request);
}

Estamos recorrendo classe FormattedContentResult<T> para retornar a instncia da


classe Artista no formato Json e com status de nmero 200 (OK). O ASP.NET entender
o retorno normalmente, e quando estivermos criando os testes unitrios para esta ao,
independente do tipo de retorno que ela internamente definda (um objeto
customizado, uma string, etc.), os testes sempre iro lidar a instncia da classe
HttpResponseMessage, e a partir dela, realizar todas as conferncias necessrias para
determinar se os testes executaram com sucesso ou no.

69
[TestMethod]
public void DeveRetornarRespostaCorreta()
{
using (var request = new HttpRequestMessage())
{
var nome = "Max Pezzali";
var response =
new ArtistasController() { Request = request }
.Get(nome)
.ExecuteAsync(CancellationToken.None)
.Result;

Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
Assert.AreEqual(nome, response.Content.ReadAsAsync<Artista>().Result.Nome);
}
}

O que vimos at agora neste captulo consiste em realizar os testes apenas nas classes
que representam os servios. Como os servios REST usam o HTTP como parte do
processo, muitas vezes somente a execuo do controller o suficiente para entender
que ele foi executado com sucesso, o que nos obriga a recorrer recursos do prprio
HTTP para complementar a tarefa que est sendo executada e, consequentemente,
tambm devemos compor isso em nossos testes.

Felizmente, pelo fato do ASP.NET Web API ser complemente desvinculado da


infraestrutura, isso nos permite considerar os objetos que representam o proxy do
cliente e o hosting do servio nos testes, e validar se ao enviar, processar e retornar uma
determinada requisio, se ela passa por todas os estgios de processamento dentro do
pipeline do ASP.NET.

Os objetos HttpServer e o HttpClient foram construdos totalmente desvinculados de


qualquer necessidade de somente execut-los em ambiente real. Com isso, podemos
fazer uso destes mesmos objetos em um projeto de testes, onde podemos simular a
mesma estrutura de objetos, suas configuraes e seus interceptadores, que ao
executar os testes, a requisio e resposta percorrero todo o fluxo que percorreria
quando ele for colocado em produo.

Para exemplificar isso, vamos considerar que temos um servio que possui apenas dois
mtodos: um onde ele adiciona um objeto Cliente em um repositrio qualquer, e outro
que dado o Id deste Cliente, ele retorna o respectivo registro. No vamos nos preocupar
neste momento com boas prticas, mas no interior do controller podemos visualizar o
repositrio criado e sendo utilizado pelos dois mtodos.

public class ClientesController : ApiController


{
private static RepositorioDeClientes repositorio = new RepositorioDeClientes();

[HttpGet]
public Cliente Recuperar(int id)
{
return repositorio.RecuperarPorId(id);
}

[HttpPost]
public HttpResponseMessage Adicionar(HttpRequestMessage request)

70
{
var cliente = request.Content.ReadAsAsync<Cliente>().Result;
repositorio.Adicionar(cliente);

var resposta = Request.CreateResponse<Cliente>(HttpStatusCode.Created,


cliente);
resposta.Headers.Location =
new Uri(string.Format("http://xpto/Clientes/Recuperar/{0}", cliente.Id));
return resposta;
}
}

Depois do servio criado resta hospedarmos e consumirmos o mesmo atravs do projeto


de testes.

[TestClass]
public class AcessoAosClientes
{
private static HttpConfiguration configuracao;
private static HttpServer servidor;
private static HttpClient proxy;

[ClassInitialize]
public static void Inicializar(TestContext context)
{
configuracao = new HttpConfiguration();
configuracao.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "{controller}/{action}/{id}"
);

servidor = new HttpServer(configuracao);


proxy = new HttpClient(servidor);
}

[TestMethod]
public void DeveSerCapazDeFazerPingComUmNovoRegistro()
{
var resultadoDaCriacao =
proxy.PostAsync(
"http://xpto/Clientes/Adicionar",
new StringContent(
"{\"Nome\":\"Israel\", \"Cidade\":\"Valinhos\"}",
Encoding.Default, "application/json"))
.Result;

Assert.AreEqual(HttpStatusCode.Created, resultadoDaCriacao.StatusCode);
Assert.IsNotNull(resultadoDaCriacao.Headers.Location);

var resultadoDaBusca =
proxy.GetAsync(resultadoDaCriacao.Headers.Location).Result;
var cliente = resultadoDaBusca.Content.ReadAsAsync<Cliente>().Result;

Assert.AreEqual(1, cliente.Id);
Assert.AreEqual("Israel", cliente.Nome);
Assert.AreEqual("Valinhos", cliente.Cidade);
}

[ClassCleanup]
public static void Finalizar()
{
proxy.Dispose();
servidor.Dispose();
}
}

71
As classes que representam o proxy e o hosting so declarados em nvel de classe
(teste). interessante notar a construo destes objetos realizada durante a
incializao da classe que representa o teste. No construtor do hosting (HttpServer)
recebe como parmetro as configuraes para o servio; j a classe HttpClient recebe
como parmetro o HttpServer, para que internamente, quando solicitarmos a requisio
para este cliente, ele encaminhe para o servio. A URI aqui pouco importa, j que o
trfego ser realizado diretamente. Isso possvel porque a classe HttpServer herda da
classe HttpMessageHandler.

Dependncias

No h como falarmos de testes unitrios sem que se tenha uma API que seja bem
construda. As boas prticas pregam que uma classe no deve ter mais responsabilidade
do que seu propsito, ou seja, se voc tem uma API que expe as msicas de um
determinado lbum, ela (a API) deve coordenar como essa listagem ser montada, mas
no responsabilidade dela conhecer detalhes, por exemplo, do banco de dados.

Ao desenhar uma classe, antes de colocar um cdigo dentro dela, necessrio analisar
se ela quem deveria realizar essa atividade. Quanto mais a classe depender de uma
abstrao ao invs de uma implementao, ser muito mais fcil substituir isso durante
a escrita dos testes. No exemplo abaixo temos um controller que necessita de um
repositrio para extrair o lbum de um artista.

public interface IRepositorio


{
Album BuscarAlbumPor(string artista);
}

public class ArtistasController : ApiController


{
private readonly IRepositorio repositorio;

public Artistas(IRepositorio repositorio)


{
this.repositorio = repositorio;
}

[HttpGet]
public Album RecuperarAlbum(string artista)
{
return this.repositorio.BuscarAlbumPor(artista);
}
}

Durante a escrita dos testes unitrios, podemos criar e passar classe Artistas uma
representao em memria do repositrio e, consequentemente, avaliar se o mtodo
RecuperarAlbum est atendendo o necessidade. A questo como isso ser realizado
durante a execuo da API.

Felizmente o ASP.NET Web API j possui internamente um local onde podemos


adicionar todas as dependncias do nosso controller, que durante a execuo, ele ser
capaz de analisar a necessidade, construir o objeto, e entreg-lo API para que seja
utilizada. Para isso temos a interface IDependencyResolver (namespace

72
System.Web.Http.Dependencies), qual podemos utilizar para customizar a criao dos
controllers, onde poderemos abastecer manualmente toda a necessidade que cada um
possui.

public class HardcodeResolver : IDependencyResolver


{
public IDependencyScope BeginScope()
{
return this;
}

public object GetService(Type serviceType)


{
if (serviceType == typeof(ArtistasController))
return new ArtistasController(new RepositorioXml("Artistas.xml"));

return null;
}

public IEnumerable<object> GetServices(Type serviceType)


{
return new List<object>();
}

public void Dispose() { }


}

Para que a classe HardcodeResolver funcione durante a execuo, temos que apontar
ao ASP.NET Web API que o objeto que criar a instncia da classe que representar a
API, resolver todas as dependncias e entregar para atender as requisies ela.
Novamente vamos recorrer ao objeto de configurao, que atravs da propriedade
DependencyResolver podemos definir qualquer classe que implemente a interface
IDependencyResolver.

config.DependencyResolver = new HardcodeResolver();

Os mtodos BeginScope e Dispose so utilizados para controlar o tempo de vida dos


objetos que so criados. Quando o controller ou qualquer objeto que ele seja capaz de
resolver e criar criado, podemos criar um objeto que define um escopo para ele, e
aps o runtime utiliz-lo, ele devolvido para que seja adequadamente descartado,
incluindo suas dependncias internas que ela possa utilizar. Isso pode ser til quando
est utilizando algum container de inverso de controle (IoC). Se os objetos criados no
tiverem a necessidade de gerenciamento de escopo para o descarte de recursos, ento
podemos retornar o this.

Tracing

Tracing a forma que temos para monitorar a execuo da aplicao enquanto ela est
rodando. Isso extremamente til para diagnosticar problemas que ocorrem em tempo
de execuo, e que geralmente, por algum motivo especfico faz com que a aplicao
no se comporte como esperado.

73
O ASP.NET Web API j traz um mecanismo de captura extremamente simples de se
trabalhar e to poderoso quanto. Tudo acaba sendo realizado atravs da interface
ITraceWriter (namespace System.Web.Http.Tracing), que dado uma implementao
dela, o ASP.NET Web API captura detalhes referentes as mensagens HTTP e submete
para que ela armazene no local de sua escolha.

Ele no vem com nenhuma implementao nativa, o que nos obriga a criar uma e
acoplarmos execuo. Isso nos permitir escolher qualquer meio de logging, como por
exemplo o log4net, ETW, Logging Application Block, System.Diagnostics, etc. Esta
interface fornece um nico mtodo chamado Trace, que recebe os seguintes
parmetros:

request: recebe o objeto HttpRequestMessage associado com as informaes


que sero coletadas.
category: uma string que determina a categoria em que as informao sero
gravadas, permitindo agrupar informaes que est relacionadas em pontos
distintos da coleta.
level: um enumerador com as opes (j conhecidas) que definem o nvel de
severidade da informao.
traceAction: representa um delegate que permite ao chamador definir qualquer
ao, que ser executada quando o mecanismo de trace decidir coletar alguma
informao.

Para termos uma ideia das informaes que so coletadas, abaixo temos um logging
que se exibe as informaes em uma aplicao console. A utilizao da aplicao console
para mostrar o funcionamento do mecanismo, mas como j falado acima, poderamos
criar vrias implementaes. Quando estamos lidando com aplicaes do mundo real,
necessrio recorrermos a alguma biblioteca j existente e que faa grande parte do
trabalho para armazenar e, principalmente, fornea uma forma simples para monitorar.

public class ConsoleLogging : ITraceWriter


{
public void Trace(HttpRequestMessage request, string category,
TraceLevel level, Action<TraceRecord> traceAction)
{
var record = new TraceRecord(request, category, level);
traceAction(record);

View(record);
}

private void View(TraceRecord record)


{
Console.WriteLine(record.RequestId);
Console.WriteLine("{0} - {1}", record.Category, record.Level);
Console.WriteLine("{0} - {1}", record.Request.Method,
record.Request.RequestUri);
Console.WriteLine("{0} - {1}", record.Operator, record.Operation);
Console.WriteLine();
}
}

74
A classe TraceRecord representa um item de rastreamento e ele que deve ser
catalogado para futuras anlises. No interior do mtodo Trace construmos o objeto
TraceRecord e antes de passarmos para o delegate traceAction, podemos customizar
com informaes especficas. E no exemplo acima, depois de configurado o
TraceRecord, exibimos as propriedades deste projeto na console:

Figura 20 - Logs sendo exibidos na console.

claro que a implementao no suficiente para que tudo isso funcione. Para que ele
seja acionado, necessrio acoplarmos execuo, e para isso, recorremos ao objeto
de configurao do ASP.NET Web API. Neste momento, tudo o que precisamos saber
para que o logging customizado funcione adicionar o seguinte comando na
configurao da API:

config.Services.Replace(typeof(ITraceWriter), new ConsoleLogging());

E para finalizar, como pudemos perceber, somente informaes inerentes aos estgios
do processamento da requisio foram logados. E se desejarmos tambm incluir
informaes referentes as regraas de negcio, ou melhor, incluir informaes que so
geradas no interior do controller? A classe ApiController possui uma propriedade
chamada Configuration, que expe o objeto de configurao a API e,
consequentemente, nos permite acessar o tracing para incluir qualquer informao que
achemos importante e necessrio para quando precisarmos monitorar.

Para facilitar a insero destas informaes customizadas, a Microsoft incluiu uma classe
esttica com mtodos de estenses interface ITraceWriter com mtodos nomeados
com as severidades

using System.Web.Http;
using System.Web.Http.Tracing;

public class TestController : ApiController


{

75
public string Get()
{
this.Configuration
.Services
.GetTraceWriter()
.Info(this.Request, "Aes", "Alguma Info", "xpto");

return "test";
}
}

Figura 21 - Informao customizada sendo exibida.

76
Arquitetura e Estensibilidade
Para que seja possvel tirar um maior proveito do que qualquer biblioteca ou framework
tem a oferecer, termos o conhecimento mais profundo de sua arquitetura. Apesar de
ser opcional no primeiro momento, de grande importncia o conhecimento destes
mecanismos, pois podem ser teis durante alguma depurao que seja necessria ou
durante a estenso de algum ponto para uma eventual customizao, algo que tambm
ser abordado neste captulo.

O entendimento da arquitetura nos dar uma viso bem detalhada do processamento


das mensagens, sabendo o ponto correto para interceptar uma requisio a fim
customizar algum elemento, interferir na escolha de alguma ao, aplicao de
segurana (autenticao e autorizao), implementar uma camada de caching, etc.
Muito desses pontos j vimos no decorrer dos captulos anteriores, e a prprio Microsoft
fez uso deles para implementar algum elementos que j esto embutidos no ASP.NET
Web API.

Antes de falarmos sobre a arquitetura do ASP.NET Web API, precisamos recapitular de


forma resumida como a infraestrutura do ASP.NET, e depois disso, veremos a
bifurcao onde temos o desvio para o MVC, Web Forms e Web API.

Tudo comea com a criao da classe HttpApplication, que o objeto que ir coordenar
e gerenciar toda a execuo das requisies que chegam para uma aplicao. Dentro
deste objeto temos uma coleo de mdulos, que so classes que implementam a
interface IHttpModule, que so como filtros onde podemos examinar e modificar o
contedo da mensagem que chega e que parte atravs do pipeline.

Depois que a mensagem passar pelos mdulos, chega o momento de escolher o handler
que tratar a requisio. O handler o alvo da requisio, que ir receber a requisio e
trat-la, e devolver a resposta. Os handlers implementam a interface IHttpHandler ou
IHttpAsyncHandler (para implementao assncrona), e existem diversas classes dentro
do ASP.NET, onde uma trata a requisio para uma pgina do Web Forms, para uma
aplicao MVC, para um servio ASMX, etc. Depois do handler executado, a mensagem
de retorno gerada, passa pelos mdulos que interceptam o retorno, e parte para o
cliente que solicitou o recurso.

Figura 22 - Caminho percorrido pela requisio nos mdulos e handlers.

77
Independentemente de qual recurso ser acessado, o estgio inicial comum para
todos eles. Tudo o que falamos at aqui vale para quando estamos utilizando o hosting
baseado na web (IIS/ASP.NET). No caso de self-hosting, onde hospedamos a API em
nosso prprio processo, o caminho para a ser igual.

Figura 23 - Comparao entre web e self-hosting.

Como h comentado anteriormente, a classe HttpSelfHostServer (que herda da classe


HttpServer), utilizada quando optamos pelo modelo de self-hosting, faz uso de recursos
fornecidos pelo WCF, e depois de coletar as informaes que chegam at o servio, ele
cria e passa adiante a instncia da classe HttpRequestMessage.

importante notar que do lado do web-hosting temos a classe HttpControllerHandler,


que a implementao da classe IHttpHandler, responsvel por materializar a
requisio (HttpRequest) no objeto do tipo HttpRequestMessage, enviando-a para a
classe HttpServer.

Depois que a requisio pela classe HttpServer, um novo pipeline iniciado, que possui
vrios pontos, e o primeiro deles chamado de Message Handlers. Como o prprio
nome diz, eles esto logo no primeiro estgio do pipeline, ou seja, independentemente
de qual sua inteno para com o servio, elas sero sempre sero executadas, a menos
que haja algum critrio que voc avalie e rejeite a solicitao, o que proibir o avano
do processamento para os prximos handlers.

Basicamente esses handlers recebem a instncia de uma classe do tipo


HttpRequestMessage, que traz toda a solicitao do usurio, e retornam a instncia da
classe HttpResponseMessage, contendo a resposta gerada para aquela solicitao. E
como j ficou subententido, podemos ter vrios handlers adicionados ao pipeline, onde
cada um deles pode ser responsvel por executar uma tarefa distinta, como logging,
autenticao, autorizao, etc. A imagem abaixo ilustra esse fluxo:

78
Figura 24 - Estrutura dos message handlers.

Para a criao que um message handler customizado, necessrio herdar da classe


abstrata DelegatingHandler. Essa classe pode receber em seu construtor um objeto do
tipo HttpMessageChannel. A finalidade deste objeto que passado no construtor, com
o intuito de cada handler seja responsvel por executar uma determinada tarefa, e
depois passar para o prximo, ou seja, uma implementao do padro Decorator.

public class ApiKeyVerification : DelegatingHandler


{
private const string ApiKeyHeader = "Api-Key";
private static string[] ValidKeys = new string[] { "18372", "92749" };

protected override Task<HttpResponseMessage> SendAsync(


HttpRequestMessage request, CancellationToken cancellationToken)
{
if (IsValidKey(request))
return base.SendAsync(request, cancellationToken);

return Task.Factory.StartNew(() =>


new HttpResponseMessage(HttpStatusCode.Unauthorized));
}

private static bool IsValidKey(HttpRequestMessage request)


{
var header = request.Headers.FirstOrDefault(h => h.Key == ApiKeyHeader);

return
header.Value != null &&
ValidKeys.Contains(header.Value.FirstOrDefault());
}
}

A classe acima intercepta a requisio e procura se existe um header chamado Api-Key.


Se no houver ou se existir e no for uma chamada vlida, ele rejeita a requisio
retornando o cdigo 401 (Unauthorized) ao cliente, que significa que ele no est
autorizado a visualizar o contedo. importante ressaltar que se a chave no for vlida,
a requisio no vai adiante, ou seja, ela j abortada quando a primeira inconsistncia
for encontrada.

79
Podemos acoplar os message handlers em dois nveis para serem executados. Eles
podem ser globais, que como o prprio nome sugere, sero executadas para todas as
requisies que chegam a API, ou serem especficos para uma determinada rota. No
primeiro caso, a instncia do message handler adicionada coleo de handlers,
atravs da propriedade MessageHandlers. J a segunda opo, recorremos um
overload do mtodo MapHttpRoute, onde em seu ltimo parmetro temos a opo de
incluir o message handler especfico para ela. Abaixo temos o exemplo de como fazemos
para utilizar uma ou outra opo:

//Global
config.MessageHandlers.Add(new ApiKeyVerification());

//Por rota
config.Routes.MapHttpRoute(
name: "Default",
routeTemplate: "api/{controller}",
defaults: null,
constraints: null,
handler:
HttpClientFactory.CreatePipeline(
new HttpControllerDispatcher(config),
new DelegatingHandler[] { new ApiKeyVerification() }));

Se encaminharmos a requisio com uma chave invlida, podemos perceber que no


somos autorizados a acessar o recurso. A partir do momento que colocamos uma chave
que o servio entende como vlida, o resultado retornado. A imagem abaixo comprova
essa anlise.

Figura 25 - Headers customizados para controle de acesso.

Existem dois message handlers embutidos no ASP.NET Web API que desempenham um
papel extremamente importante no pipeline. O primeiro deles HttpRoutingDispatcher,
que avalia se existe um message handler especfico para a rota que foi encontrada. Se
houver, ele deve ser executado.

80
Caso no seja, a requisio e encaminhada para um outro message handler chamado
HttpControllerDispatcher. Uma vez que passamos por todos os handlers configurados,
este ser responsvel por encontrar e ativar o controller. No cdigo acima mencionamos
a classe HttpControllerDispatcher quando configuramos o message handler
ApiKeyVerification em nvel de rota.

A procura, escolha e ativao do controller so tarefas realizadas por elementos que


tambm so estensveis. Eles so representados pelas seguintes interfaces:
IHttpControllerSelector e IHttpControllerActivator. Depois do controller encontrado, o
momento de saber qual ao (mtodo) dentro dele ser executada. Da mesma forma,
se quisermos customizar, basta recorrer a implementao da interface
IHttpActionSelector.

Acima vimos os message handlers no contexto do lado do servidor, mas pela simetria
que existe na codificao do servidor comparado ao cliente, podemos recorrer aos
mesmos recursos para interceptar e manipular tanto a requisio quanto a resposta do
lado do cliente. O construtor da classe HttpClient pode receber como parmetro a
instncia de uma classe do tipo HttpMessageHandler. Ao omitir qualquer inicializao,
por padro, o handler padro o HttpClientHandler, que herda de
HttpMessageHandler, que responsvel pela comunicao com o HTTP, j em nvel de
rede.

Se quisermos customizar, incluindo handlers para analisar e/ou alterar a sada ou o


retorno da requisio no cliente, podemos recorrer ao mtodo de estenso chamado
Create da classe HttpClientFactory, que recebe um array contendo todos os handlers
que sero disparados, quais sero disparados em ordem inversa ao que inserido na
coleo. Este mesmo mtodo faz o trabalho para tambm inserir o handler
HttpClientHandler que se faz necessrio em qualquer situao.

using (var client =


HttpClientFactory.Create(new ValidacaoDeSessao()))
{
//...
}

public class ValidacaoDeSessao : DelegatingHandler


{
//...
}

81
Figura 26 - Estrutura dos message handlers do lado do cliente.

Apesar do controller e a ao dentro dele terem sido encontrados, podemos ainda


realizar alguma espcie de interceptao para que ainda faamos alguma tarefa antes
de executarmos a ao. Eis que surgem os filtros, que servem como uma forma de
concetrar alguuns elementos de cross-cutting, como segurana, traduo de excees
em erros HTTP, etc.

Os filtros podem ser aplicados em aes especficas dentro do controller, no controller


como um todo, ou para todas as aes em todos os controllers (global). O benefcio que
temos na utilizao de filtros a granularidade onde podemos aplic-los. Talvez
interromper a requisio logo nos primeiros estgios (via handlers) possa ser mais eficaz,
pois muitas vezes voc no precisa passar por todo o pipeline para tomar essa deciso.

H um namespace chamada System.Web.Http.Filters, que possui vrios filtros j


predefinidos. Todo filtro herda direta ou indiretamente da classe abstrata
FilterAttribute, que j possui a estrutura padro para todos os filtros. O diagrama abaixo
ilustra essa hierarquia.

Figura 27 - Hierarquia das classes dos filtros existentes dentro do framework.

82
Alm da classe base para os filtros, j temos algumas outras, tambm abstratas, que
definem a estrutura para que seja criado um filtro para controlarmos a autorizao,
outro para controlarmos o tratamento de erros e um que nos permite interceptar a
execuo de alguma ao dentro do controller.

Para e exemplificar a customizao de um filtro, podemos criar um que impossibilite o


acesso uma ao se ela no estiver protegida por HTTPS. A classe ActionFilterAttribute
fornece dois mtodos que podemos sobrescrever na classe derivada: OnActionExecuting
e OnActionExecuted. Como podemos perceber, um deles disparado antes e o outro
depois da ao executada.

public class ValidacaoDeHttps : ActionFilterAttribute


{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var request = actionContext.Request;

if (request.RequestUri.Scheme != Uri.UriSchemeHttps)
{
actionContext.Response =
request.CreateResponse(
HttpStatusCode.Forbidden,
new StringContent(" necessrio que a requisio seja HTTPS."));
}
}
}

O fato da classe ActionFilterAttribute herdar da classe Attribute, podemos aplicar este


atributo tanto no controller quanto em um ou mais aes, ou seja, podemos ter um
refinamento mais apurado, pois temos condies de aplicar isso em certos casos, em
outros no. No exemplo abaixo optamos apenas por proteger por HTTPS a ao Teste2.
Se quisermos que todos as aes dentro deste controller sejam protegidas, basta apenas
elevarmos o atributo, decorando a classe com o filtro criado.

public class TestController : ApiController


{
[HttpGet]
public string Teste1()
{
return "teste1";
}

[HttpGet]
[ValidacaoDeHttps]
public string Teste2()
{
return "teste2";
}
}

Finalmente, se desejarmos que este atributo seja aplicado em todas as aes de todos
os controllers, adicionamos este filtro em nvel global, atravs da configurao da API:

config.Filters.Add(new ValidacaoDeHttps());

83
Sobrescrita de Filtros

Ao aplicar o filtro em nvel global, evita termos que decorarmos cada (nova) ao ou
cada (novo) controller com um determinado atributo, evitando assim que, por algum
descuido, um determinado cdigo deixe de rodar antes e/ou depois de cada ao. Sendo
assim, o nvel global nos permite aplicar incondicionalmente para todas as aes, e se
quisermos aplicar um filtro para uma ou outra ao, decoramos o atributo diretamente
nele.

S que ainda h uma outra situao, que quando precisamos aplicar determinados
filtros para a grande maioria das aes, mas em poucas delas no queremos que o filtro
seja aplicado. Para isso, quando configurarmos um filtro em nvel global, podemos
sobrescrever uma determinada ao para que os filtros no sejam aplicados nela. Para
isso, entra em cena um atributo chamado OverrideActionFiltersAttribute, que quando
aplicado em uma determinada ao, ele ignora os filtros aplicados em nvel global.

public class TestController : ApiController


{
[HttpGet]
public string Teste1()
{
return "teste1";
}

[HttpGet]
[OverrideActionFilters]
public string Teste2()
{
return "teste2";
}
}

Alm deste atributo, temos outros trs com a mesma finalidade, ou seja, interromper a
execuo de determinados tipos de filtros que foram aplicados em nvel global. Os
outros atributos que temos para isso so: OverrideAuthenticationAttribute,
OverrideAuthorizationAttribute e OverrideExceptionAttribute.

Configuraes

Durante todos os captulos vimos diversas configuraes que so realizadas em nvel


global. Para todas elas recorremos ao objeto HttpConfiguration. Ele fornece diversas
propriedades e mtodos que nos permite interagir com todos os recursos que so
utilizados durante a execuo das APIs. Uma das propriedades que vale ressaltar a
Services do tipo ServicesContainer. Essa classe consiste em armazenar todos os recursos
que so utilizados pelo ASP.NET Web API para fornecer ao runtime os responsveis por
executar cada tarefa especfica, tais como: criao do controller, gestor de
dependncias, gestor de tracing, etc.

84
Figura 28 - Classes para a customizao das configuraes.

A propriedade Services da classe ServicesContainer inicializada com a instncia da


classe DefaultServices, que vale para todos e qualquer controller dentro da aplicao.
Podemos variar certas configuraes para cada controller, e justamente para isso que
temos a classe ControllerServices.

Se quisermos customizar a configurao por controller, onde cada um deles possui uma
necessidade especfica, basta implementarmos a interface IControllerConfiguration
(namespace System.Web.Http.Controllers), onde atravs do mtodo Initialize,
realizamos todas as configuraes especficas, e durante a execuo o ASP.NET ir
considerar essas configuraes, sobrescrevendo as globais, e para aquelas que no
alterarmos, a configurao global ser utilizada.

public class ConfiguracaoPadrao : Attribute, IcontrollerConfiguration


{
public void Initialize(
HttpControllerSettings controllerSettings,
HttpControllerDescriptor controllerDescriptor)
{
controllerSettings.Formatters.Add(new CsvMediaTypeFormatter());
}
}

[ConfiguracaoPadrao]
public class TestController : ApiController
{
//aes
}

85

Você também pode gostar