e-Book – Introdução ao ASP.NET Web API

Este e-Book tem a finalidade de introduzir a tecnologia ASP.NET Web API, abordando desde a sua estrutura, arquitetura até as suas principais funcionalidades e utilizações. De uma forma bastante simples, tentei resumir os principais itens, com exemplos práticos de utilização, que podem ser transcritos para um projeto no Visual Studio e executá-los.

Publicamente quero agradecer imensamente ao Elemar Junior (que dispensa apresentações), por prontamente atender ao meu pedido para escrever o prefácio deste livro. Fiquei extremamente honrado.

Estou disponibilizando este e-Book de forma gratuita, podendo ser baixado clicando aqui. Use-o como quiser. Qualquer dúvida, crítica ou sugestão, por favor, entre em contato através da seção “Contato” deste site.

HttpClient na Portable Class Library

É comum termos a necessidade de criar uma biblioteca com algum código que seja compartilhado entre diversos projetos. Para isso, recorremos à uma template de projeto chamada Class Library, em que seu output é um arquivo do tipo DLL, que pode ser referenciado e, consequentemente, utilizado por projetos que queiram utilizar a funcionalidade exportada por ela.

Tudo isso funcionará até o momento em que precisarmos expor uma determinada funcionalidade para diferentes plataformas, algo muito comum hoje no desenvolvimento de aplicações dentro do ambiente Microsoft. Possuimos diversos alvos que podemos atingir, como por exemplo: aplicações .NET, aplicações para telefones, aplicações para jogos (XBox), aplicações para tablets, etc. Apesar de existir certa simetria em alguns pontos, em outros já podem não ter tantas semelhanças assim, o que torna difícil o controle manual durante a escrita de uma biblioteca para atender qualquer uma estas plataformas.

Desde 2010 a Microsoft trabalha em um projeto para a criação de bibliotecas que possam ser compartilhadas entre diferentes plataformas, e com o Visual Studio 2012, já temos uma template de projeto exclusiva para isso: Portable Class Library. Ao criar um projeto deste tipo, você será obrigado a informar com quais tipos de projetos deseja que ela seja compatível. Isso garantirá com que você somente utilize membros que sejam comuns entre todas as plataformas selecionadas.

Geralmente algumas informações e funcionalidades estão expostas para serem consumidas remotamente, entre os mais diversos dispositivos. Sendo assim, é muito comum termos a necessidade de consumir os serviços expostos pela própria empresa, parceiros de negócios, etc., afim de reutilizar recursos que já estejam construídos e disponibilizados por terceiros. E como já era de se esperar, APIs REST estão cada vez mais populares, e ter um mecanismo para o consumo de forma simples destes tipos de serviços é essencial em qualquer plataforma.

Sabendo disso, a Microsoft criou uma classe chamada HttpClient, que é utilizada para abstrarir toda a complexidade na interação com APIs REST, e mais recentemente, a Microsoft criou a versão portável desta mesma classe. Com isso, poderemos reutilizar o consumo de APIs REST (HTTP) através de diferentes plataformas, sem a necessidade de reconstruir a cada novo projeto uma ponte de comunicação com estes tipos de serviços, e ainda, sem a necessidade de recorrer de classes de mais baixo nível para atingir o mesmo objetivo.

Em princípio a classe HttpClient fornece as mesmas funcionalidades expostas desde a sua criação, acrescentando alguns poucos métodos que expõem alguma funcionalidade específica para uma determinada plataforma. Para utilizar essa DLL em algum dos seus projetos (incluindo bibliotecas portáveis customizadas (Portable Class Libraries)), basta você adicionar o pacote “Http Client Libraries”, conforme mostrado na imagem abaixo:

Características do ASP.NET Web API

Como o ASP.NET Web API é implementando sobre o ASP.NET MVC, muitas das funcionalidades que o MVC possui, foram reutilizadas pelo Web API, para que os mesmos recursos e a mesma forma de configuração sejam equivalentes, não importando se estamos desenvolvendo um site ou uma API para ser exposta e consumida pelos clientes.

Entre as funcionalidades mais comuns, temos o envio de tipos complexos, ou seja, a capacidade das aplicações criarem objetos, definir seus atributos, e submetê-los ao serviço. Isso nos permite criar objetos que descrevem o nosso negócio, tornando bem mais intuitivo que criar um método com vários parâmetros. Além disso, nem sempre o serviço rodará sem qualquer problema; durante a execução vários tipos de exceção podem acontecer, e o tratamento por parte do serviço e a formatação da resposta precisam ser cuidadosamente pensadas, afinal, precisamos no basear nos códigos do HTTP para reportar o problema. Finalmente, muitas vezes as APIs recorrem a recursos externos, tais como: leitura/escrita de arquivos, leitura/escrita de dados no banco de dados, etc., e ao invés do serviço depender diretamente da implementação, podemos fazer com ele dependa de uma abstração, que durante a execução, o objeto concreto é injetado. Para isso, podemos recorrer aos serviços de injeção de dependência, que já estão espalhados pelo ASP.NET Web API, e que nos permitirá customizar várias situações, em pontos distintos.

A ideia deste artigo é introduzir cada um destes tópicos, com detalhes de implementação, ao qual poderemos recorrer durante a construção das nossas APIs.

Model Binding

As aplicações geralmente trabalham com objetos que descrevem suas características, onde estes objetos são manipulados o tempo todo, já que na grande maioria dos casos, ela acaba também sendo persistido no banco de dados, apresentado na tela, etc. Como esses objetos são parte do core da aplicação, é muito comum criarmos formulários que apresente a instância no mesmo na tela (HTML), para que o usuário seja capaz de editá-lo.

Ao submeter o formulário para o servidor, todas as informações (querystrings, body, URI, etc.) chegam através de um dicionário, onde cada valor está associado à uma chave. Ao invés de manualmente construirmos a instância da classe baseada no corpo da requisição, o ASP.NET MVC já fez esse árduo trabalho para nós, e o responsável por isso são os model binders. Baseando-se na action para qual estamos postando a requisição, ele captura o tipo do objeto que precisa ser criado, mapeando o dicionário para cada uma de suas propriedades.

Quando utilizamos o ASP.NET Web API, não é diferente, ou seja, quando o nosso serviço espera um objeto complexo, o ASP.NET faz o trabalho para entregá-lo já materializado para nós. Neste caso, há como recebermos a postagem de um formulário HTML, mas também temos que nos atentar, que na maioria das vezes, vamos lidar com o conteúdo em formato XML ou JSON.

Os formatters, já discutido anteriormente, executam um papel importante aqui. Apesar da tecnologia ter sido readequada para o ASP.NET, os principais formatters foram mantidos: FormUrlEncodedMediaTypeFormatter, JsonMediaTypeFormatter e o XmlMediaTypeFormatter. Baseando-se no header Content-Type da própria requisição, ele escolhe qual destes formatters irá utilizar para extrair as informações do corpo da mensagem, e na sequência, encaminha as informações para que o model binder faça a criação do objeto e, consequentemente, atribua os respectivos valores.

Levando em consideração que temos uma ação que receba como parâmetro a instância da classe Cliente, que por sua vez, possui duas propriedades (Nome e Email), podemos postar o conteúdo em qualquer formato, e desde que haja um formatter para o tipo de conteúdo submetido (Content-Type), o ASP.NET Web API também será capaz de transformá-lo em algo concreto. Abaixo temos a assinatura da ação, e na sequência, os posts efetuados com os diferentes formatos.

[HttpPost]
public void Adicionar(Cliente cliente) { }

[ Via Formulário ]

POST http://localhost:1062/api/clientes/Adicionar HTTP/1.1
User-Agent: Fiddler
Content-Type: application/x-www-form-urlencoded
Host: localhost:1062
Content-Length: 35

Nome=Israel&Email=ia@israelaece.com

[ Via JSON ]

POST http://localhost:1062/api/clientes/Adicionar HTTP/1.1
User-Agent: Fiddler
Content-Type: application/json
Host: localhost:1062
Content-Length: 48

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

[ Via XML ]

POST http://localhost:1062/api/clientes/Adicionar HTTP/1.1
User-Agent: Fiddler
Content-Type: application/xml
Host: localhost:1062
Content-Length: 70

<Cliente><Nome>Israel</Nome><Email>ia@israelaece.com</Email></Cliente>

Validações

Uma vez que o model binder foi capaz de construir o objeto baseando-se na requisição, um passo, que pode ser opcional, é a validação desse objeto, que consiste em saber se todas as propriedades do mesmo foram extraídas da requisição, e estão com seus valores definidos conforme esperado.

Novamente, assim como no ASP.NET MVC, o Web API também pode confiar nos Data Annotations do .NET Framework para validar se o objeto encontra-se em um estado válido. Para isso, basta decorarmos as propriedades com os mais variados atributos que existem debaixo do namespace System.ComponentModel.DataAnnotations. Só que apenas isso não é suficiente, pois na versão atual (Beta), o ASP.NET Web API não executa automaticamente as validações, e sendo assim, precisamos interceptar a requisição, e antes da ação ser executada, validarmos se o estado do objeto está ou não válido.

Para isso, temos que criar um filtro herdando de ActionFilterAttribute, sobrescrevendo o método OnActionExecuting. Como parâmetro recebemos a instância da classe HttpActionContext, que como o próprio nome diz, traz informações pertinentes ao contexto da requisição atual. Entre as várias propriedades, ela expõe uma chamada de ModelState, que define um dicionário contendo o estado do modelo e determina se o mesmo passou ou não nas eventuais regras de validação que foram definidas.

Com isso, podemos facilmente recuperar os detalhes das validações realizadas, e repassá-las para que o cliente possa ter informações precisas sobre os problemas que aconteceram. Para interrompermos a execução, basta criar uma mensagem de resposta (HttpResponseMessage), definindo que a requisição não está de acordo com o esperado, e atribuí-la a propriedade Response do contexto. Abaixo temos a implementação deste atributo:

public class ModelValidationAtribute : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext ctx)
    {
        if (!ctx.ModelState.IsValid)
        {
            ctx.Response =
                new HttpResponseMessage<IEnumerable<ErrorDetails>>
                (
                    from e in ctx.ModelState.Values
                    where e.Errors.Count > 0
                    select new ErrorDetails()
                    {
                        Message = e.Errors.First().ErrorMessage
                    },
                    HttpStatusCode.BadRequest
                );
        }
    }
}

Para injetá-lo na execução, podemos decorar diretamente na classe (controller) ou no método (action), ou como é algo comum para qualquer ação do serviço, podemos definí-lo como um filtro global, que automaticamente será executado por toda e qualquer ação que é executada naquela aplicação. O trecho do código abaixo foi adicionado ao arquivo Global.asax, para que o filtro seja adicionado à aplicação durante o início da mesma.

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

Um detalhe interessante é com relação a negociação do conteúdo. Se houver algum problema, é importante que o runtime devolva a resposta ao cliente de acordo com o tipo que ele aceita. Ele olhará para o header Accept para determinar em que formato ele devolverá o conteúdo ao cliente, e com isso, o nosso filtro fica completamente isento em relação à detalhes de formatação da resposta. Abaixo temos a requisição sendo rejeitada pelo serviço:

[ Via JSON ]

HTTP/1.1 400 Bad Request
Content-Type: application/json; charset=utf-8
Date: Tue, 06 Mar 2012 11:30:41 GMT
Content-Length: 43

[{“Message”:”The Nome field is required.”}]

[ Via XML ]

HTTP/1.1 400 Bad Request
Content-Type: application/xml; charset=utf-8
Date: Tue, 06 Mar 2012 11:28:46 GMT
Content-Length: 255

<?xml version=”1.0″ encoding=”utf-8″?>
<ArrayOfErrorDetails xmlns:xsi=”…” xmlns:xsd=”…”>
    <ErrorDetails>
        <Message>The Nome field is required.</Message>
    </ErrorDetails>
</ArrayOfErrorDetails>

Tratamento de Erros

Durante a execução, uma porção de exceções podem acontecer, sejam elas referentes à infraestrutura ou até mesmo à alguma regra de negócio, e o não tratamento correto delas, fará com as mesmas não sejam propagadas corretamente ao cliente que consome a API. A maior preocupação aqui é mapear o problema ocorrido para algum código HTTP correspondente.

Tratar as exceções in-place pode não é uma saída elegante, devido a redundância de código. Para facilitar, podemos centralizar o tratamento em nível de aplicação, o que permitirá com que qualquer exceção não tratada no interior da ação, 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 espécie de tradução, para tornar a resposta coerente ao que determina os códigos do HTTP, como por exemplo: se algum erro relacionado à autorização, devemos definir como resposta 403 (Forbidden); já se algum informação está faltante (assim como vimos no exemplo acima), devemos retornar (400) BadRequest; já se o registro procurado não foi encontrado, ele deverá receber o código 404 (NotFound), e assim por diante.

Da mesma forma que vimos acima, aqui também vamos recorrer a criação de um filtro customizado para centralizar a tradução de algum problema que acontecer. Só que neste caso, temos uma classe abstrata chamada de ExceptionFilterAttribute, que já fornece parte da infraestrutura necessária 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 método OnException e definir toda a regra de tradução necessária. Abaixo um exemplo simples de como proceder para realizar esta customização:

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);
    }
}

Assim como no caso do validação que vimos acima, podemos aplicar este atributo em nível de classe (controller) ou de método (action), mas como o tratamento é, geralmente, comum para todos os serviços que rodam dentro da aplicação, então podemos, novamente, aplicar em nível global, assim como é mostrado no código a seguir:

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

Injeção de Dependências

Quando criamos a classe que representará a API, definimos os métodos que serão expostos para os clientes. No interior destes métodos, vamos escrever o código necessário para atender a necessidade dos mesmos, seja calculando, persistindo ou devolvendo alguma informação que é exigida por ele.

Com isso, é extremamente comum que a classe que representa a API necessite recorrer a recursos externos para executar qualquer uma dessas ações, como por exemplo: se ele necessitar salvar alguma informação no banco de dados, precisamos da classe responsável por realizar isso (repositório). O mesmo acontecerá quando ele necessite de alguma informação, pois muito provavelmente, recorreremos a este mesmo repositório.

Todas as funcionalidades e/ou informações que a API precise, e que não seja de responsabilidade dela gerenciar, ela dependerá disso para cumprir o seu objetivo. Com isso, de alguma forma precisaremos injetar essas dependências na API, e com isso, torná-la independente de qualquer implementação concreta, para que se tenha flexibilidade e que facilite os testes.

Como a criação do controller que representa a API é feita pelo próprio ASP.NET, a Microsoft deixou alguns pontos em que podemos customizar a criação do mesmo, e com isso, temos a possibilidade de criarmos a dependência exigida pela API, ou se ainda desejar, recorrer a algum container de injeção de dependência de sua preferência, para que ele contemple e gerencia todas as dependências daquela aplicação.

Incrementando a API que utilizamos acima, ela precisa de um repositório para ler/persistir os clientes no banco de dados. Sendo assim, vamos mudar a API e colocar um construtor exigindo o tal repositório, já que é o mínimo que ela precisa para poder desempenhar a sua atividade.

public class Clientes : ApiController
{
    public Cliente(IRepositorioDeClientes repositorio)
    {
        //…
    }

    [HttpPost]
    public void Adicionar(Cliente cliente)
    {
        //…
        repositorio.Adicionar(cliente);
    }
}

ASP.NET Web API recorre a um resolver, e que podemos fornecer a nossa própria implementação, nos permitindo determinar a forma como construímos as dependnências (incluindo dependências relacionadas à infraestrutura), ou ainda, como disse acima, recorrer à utilização de algum container de DI, e você verá que isso é muito próximo ao padrão que já temos implementado com o ASP.NET MVC. Para customizarmos, basta criarmos uma classe que implemente a interface IDependencyResolver, qual fornece dois métodos autoexplicativos: GetService e GetServices. Abaixo uma implmentação simples deste resolvedor:

public class HardcodeResolver : IDependencyResolver
{
    public object GetService(Type serviceType)
    {
        if (serviceType == typeof(ClientesController))
            return new ClientesController(new RepositorioDeClientes());

        return null;
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        return new List<object>();
    }
}

Da mesma forma, como grande parte dos recursos que vimos acima, a criação desta classe não é suficiente para poder funcionar, pois precisamos incorpora-la à execução. O ASP.NET Web API fornece uma classe que gerencia a configuração das APIs que rodam na aplicação, e ela é chamada de HttpConfiguration. Esta classe possui vários membros, e entre eles expõe uma propriedade chamada de ServiceResolver, que como o próprio nome sugere, é utilizada para resolver os serviços requeridos pelo serviço.

Nesta classe existe um método chamado SetResolver, que como parâmetro recebe uma classe que implemente a interface IDependencyResolver. É por este ponto de estensibilidade que plugamos a classe que criamos para resolver as dependências. O código abaixo exibe como procedemos para colocá-la em execução:

GlobalConfiguration
    .Configuration
    .ServiceResolver
    .SetResolver(new HardcodeResolver());

Há também um overload deste mesmo método que nos permite passar, via lambdas, o método que deverá criar a instância das dependências, não precisando assim criar uma classe específica para isso. Abaixo temos a mesmo exemplo só que utilizando esta outra opção:

GlobalConfiguration
    .Configuration
    .ServiceResolver
    .SetResolver
    (
        serviceType =>
        {
            if (serviceType == typeof(ClientesController))
                return new ClientesController(new RepositorioDeClientes());

            return null;
        },
        serviceType => return new List<object>()
    );

Um detalhe importante aqui é que quando a dependência não for resolvida, o ASP.NET Web API espera que retornemos um valor nulo ao invés de disparar uma exceção. Retornando nulo, fará com que o runtime escolha alguma implementação padrão, caso ela exista.

A classe DependencyResolver ainda lida com diversos outros recursos que são utilizados pela própria infraestrutura do ASP.NET Web API. Isso quer dizer que o Web API também recorre a este mesmo objeto, para buscar recursos que ele precisa para funcionar, e com isso, podemos utilizá-lo para inserir as customizações que desenvolvemos quando queremos alterar alguma configuração/comportamento diferente do padrão.

ASP.NET Web API – Overview

Como mencionei anteriormente, a partir da versão 4, o ASP.NET MVC passará a ter uma infraestrutura completa para a construção e hospedagem de serviços REST. Apesar de essencialmente ser baseado em uma template Web, há algumas mudanças em como implementar o serviço em relação a como fazíamos no WCF Web API.

Ao instalar essa versão, que ainda encontra-se em Beta, passamos a ter uma template de projeto chamada ASP.NET MVC 4, e ao selecioná-la, uma segunda tela é exibida para escolhermos uma entre as seis opções disponíveis, sendo que uma delas é a Web API. Basicamente, cada uma delas traz um projeto pré-configurado com os recursos necessários para que ele funcione corretamente.

Se começarmos a explorar esta template, já começamos a nos deparar com alguns destes recursos configurados. Em primeiro lugar, podemos notar a existência de novos assemblies, que são utilizamos para a construção de APIs Web. Entre eles, o principal é o System.Web.Http.dll, que possui grande parte dos tipos que são utilizados por estes serviços, incluindo tipos que serão utilizados diretamente pelo serviço, bem como tipos que são utilizados pela infraestrutura e pipeline.

Como estamos utilizando a infraestrutura do ASP.NET MVC, as classes que servirão como serviços, deverão herdar da classe abstrata ApiController, que possui características diferentes do Controller tradicional, próprio do MVC; e este novo controller fornece detalhes específicos para a construção de serviços. Os métodos que estarão acessíveis pelos clientes, serão métodos (ações) que estarão dentro desta classe, e que através do sistema de roteamento, deverá procurar e encontrar pela classe/método de acordo com a URI informada.

Dentro desta classe podemos receber e/ou retornar tipos simples, bem como tipos complexos, que são aquelas classes que criamos para representar nossas entidades. Se precisarmos de um acesso mais refinado, da requisição ou da resposta, podemos recorrer ao uso das classes HttpRequestMessage<T> e HttpResponseMessage<T>, mas que infelizmente na versão atual (ainda em Beta), não há nenhum model binder que faz conversão da requisição em um objeto do tipo HttpRequestMessage<T>, mas segundo o time, isso será resolvido em futuras versões. Se precisarmos acessar informações pertinentes à requisição, então devemos recorrer à propriedade Request diretamente, exporta pela classe ApiController. Abaixo temos um exemplo simples de como fica a classe que conterá os métodos de exemplo:

public class NoticiasController : ApiController
{
private static IList<Noticia> noticias = new List<Noticia>();

public IQueryable<Noticia> Get()
{
return noticias.AsQueryable();
}

public Noticia Post(Noticia noticia)
{
noticias.Add(noticia);
return noticia;
}
}

Com essa implementação, já é tudo o que precisamos para poder consumi-lo em uma aplicação cliente. Há um detalhe que passa despercebido no código acima, que é a nomenclatura dos métodos. Note que propositalmente nomeamos o primeiro como Get e o segundo como Post, que refletem dois dos mais comuns verbos do protocolo HTTP.

Na verdade, como parte da template do projeto, já há uma configuração no arquivo Global.asax, que determina uma rota padrão para os serviços. Copiei abaixo a configuração, e podemos notar que há espaço para o controller, mas nada é mencionado em relação ao método/ação na rota. Existem algumas deduções que ele faz, como por exemplo, verificar se dentro do controller há um método, sem parâmetros, onde o nome inicie com “Get…”. O mesmo coisa acontece com o método Post e também para os outros métodos GET e PUT do HTTP.

routes.MapHttpRoute(
name: “DefaultApi”,
routeTemplate: “api/{controller}/{id}”,
defaults: new { id = RouteParameter.Optional }
);

Se desejar definir um nome diferente destas regras, você pode recorrer aos atributos HttpGetAttribute, HttpPostAttribute, HttpPutAttribute e HttpDeleteAttribute, para dizer ao framework o que e como pode ser acessado um determinado método dentro desta classe.

Algumas funcionalidades inerentes ao HTTP já estão devidamente configuradas, como por exemplo, basta apontar o header Content-Type ou Accept, do tipo do conteúdo ou tipo da resposta, respectivamente, e o ASP.NET Web API já sabe como deve ler/gerar o conteúdo. Além disso, já existe suporte nativo a alguns operadores do protocolo OData, como paginação, ordenação, etc., e para tudo isso funcionar, a única preocupação é que nosso método retorne a instância de uma classe que implemente a interface IQueryable<T>, e a partir daí, é só incorporar na querystring os parâmetros necessários.

Finalmente, podemos perceber neste pequeno trecho de código, que a construção de um serviço REST acaba ficando mais simples se comparado ao WCF Web API, e muito mais simples ainda, se compararmos com o WCF HTTP.

WCF Web API agora é ASP.NET Web API

Por algum tempo eu venho falando sobre um novo projeto da Microsoft chamado de WCF Web API, que trata-se de um espécie de estensão do WCF que facilita a construção e o consumo de serviços que são puramente Web (REST), ou seja, estão fortemente amarrados ao protocolo HTTP e o assumem como uma camada de aplicação. Abaixo temos alguns dos artigos que escrevi e que abordam essa tecnologia:

Apesar de possuir uma forma de hospedar esse tipo de serviço através de uma aplicação do tipo Windows (Windows Service, Console, etc.), a sua forma mais natural é utilizar o IIS, ou melhor, utilizar qualquer template de aplicação ASP.NET e lá criar a classe que representará o serviço, e apenas com uma linha de código, é o suficiente para mapear uma URI base para o serviço e tudo magicamente funciona, sem a necessidade de uma configuração extra no arquivo Web.config.

Foi a partir deste momento que nos perguntarmos porque não utilizar o próprio ASP.NET MVC? Com o ASP.NET você tem acesso a todo conjunto de recursos do HTTP, já que projetos Web tem afinidade com este protocolo. Além disso, a necessidade que os scripts tem em invocar um método C#, fez com que a Microsoft criasse um tipo de resultado chamado de JsonResult, qual retorna um valor “facilmente legível” para o Javascript.

Haviam certos overlaps entre o WCF Web API e o ASP.NET MVC, onde cada um deles determina uma forma específica de utilizar o mesmo protocolo, que é o HTTP. Então, para remover essa confusão, a Microsoft decidiu juntar essas duas tecnologias, e daí surgiu o ASP.NET Web API.

Com essa mesclagem alguns dos elementos que compunham o WCF Web API não existirão mais, justamente porque o ASP.NET MVC trata de outra forma. No ASP.NET Web API, agora vamos lidar com controllers e actions ao invés de uma classe decorada com o atributo ServiceContractAttribute e de métodos decorados com WebGetAttribute/WebInvokeAttribute. O roteamento do ASP.NET será utilizado para direcionar as requisições aos serviços. O model binding será o responsável por materializar o corpo da requisição em objetos complexos que, eventualmente, receberemos em nossos métodos. As actions filters serão utilizados ao invés de operation handlers, e ainda em tempo, se quisermos manipular complementamente a mensagem de requisição/resposta, continuamos tendo acesso às classes HttpRequestMessage e HttpResponseMessage.

Particularmente, eu gosto mais da ideia de ter um único framework que aborda os mais diferentes tipos de comunicação ao invés de atrelar isso especificamente a um tipo de projeto, mas também sou capaz de compreender a necessidade que a Microsoft tem de apartar isso, afinal, o WCF foi construído quando todos pensavam que o protocolo SOAP seria a solução para todo e qualquer tipo de comunicação existente, e o protocolo HTTP só seria mais um meio de transporte. Mas como percebemos ao longo do tempo, em certas ocasiões, ele é extremamente overkill. Mas é importante dizer que há funcionalidades que o SOAP possui que são bem interessantes, e se utilizadas da forma correta, podem trazer vários benefícios, mesmo em ambientes homogêneos. De qualquer forma, em posts futuros mostrarei como procedemos para construir serviços através desta nova tecnologia, que é o ASP.NET Web API.

Introdução ao CORS

Nos dias de hoje vivemos em um mundo cada vez mais conectado (virtualmente falando), o que nos faz criar sites e aplicações que consumam ou forneçam informações uns aos outros, tendo um conteúdo mais consistente, reutilizável e, principalmente, sincronizado. Sendo assim, existem diversas fontes de informação ao redor do mundo, que provê os mais variados conteúdos que podemos consumir em nossas aplicações.

Só que trazendo isso para o lado técnico, nos deparamos com uma grande limitação (por questões de segurança), que é o consumo de informações por parte de uma aplicação Web, onde ela somente está autorizada a consumir dados que são disponibilizados a partir do mesmo domínio de onde ela se originou (Same Origin Policy).

Uma das alternativas que temos atualmente para burlar isso, é a utilização do JSONP. Com este recurso, podemos efetuar requisições GET para um determinado recurso, mesmo que esteja além do domínio de origem, e conseguiremos recuperar as informações desejadas. O problema do JSONP é que ele somente trabalha com o verbo GET, ou seja, outros verbos não são suportados, nem mesmo o POST, já que a requisição JSONP faz uso da tag <script />, levando os parâmetros somente via querystring.

Mais cedo ou mais tarde vamos nos deparar com a necessidade de submeter algo além de simples GETs para um servidor. Para resolvermos isso, existe uma solução que está lentamente se tornando uma saída viável, é o CORS (Cross-Origin Resource Sharing). Basicamente, o CORS é uma especificação que está sendo criada e regida pelo W3C, qual define uma forma de acesso à recursos que estão em diferentes domínios.

O CORS é implementado no objeto XmlHttpRequest, e a ideia por trás dele é o uso de headers customizados que são injetados na requisição e resposta do HTTP, e que faz com que o cliente (navegador) e o servidor se conheçam, afim de determinar se a requisição deve ou não ser executada com sucesso, sendo algo mais ou menos como acontece com o Client Access Policy do Silverlight.

Observação: Apesar do XmlHttpRequest ser comum para todos os navegadores, infelizmente no caso do Internet Explorer, esse recurso é implementado em um objeto separado, chamado de XDomainRequest. Com isso, ele nos obriga a criar um código diferenciado caso estejamos rodando o código no navegador da Microsoft. A novidade é que o time do IE, recentemente publicou em seu blog, que o CORS está sendo implementado diretamente no objeto XmlHttpRequest, ficando compatível com a grande maioria dos navegadores do mercado.

Ao invés de utilizar diretamente estes objetos, podemos recorrer ao jQuery, que graças à um recurso chamado de detecção de funcionalidades, ele é capaz de detectar a presença dos objetos mencionados acima, e se existirem, podem fazer uso dele. No caso do CORS não é diferente, e vamos utilizá-lo aqui para mostrar como podemos proceder para consumir um recurso que está em outro domínio. Para o exemplo, considere o diagrama abaixo:

Como mencionei acima, é através da verificação dos headers na requisição/resposta, que o navegador decide se pode ou não concluir o processo. Se interceptarmos a requisição que é realizada, podemos notar as informações que são trocadas, incluindo os “novos” headers. Abaixo temos a requisição e a resposta, mas omitindo algumas informação irrelevantes para a explicação:

[ Requisição ]
GET http://localhost:5342/Servicos/ViaGet?valorDeEnvio=abc HTTP/1.1
Host: localhost:5342
Origin: http://localhost:5560
Referer: http://localhost:5560/Index.htm

[ Resposta ]
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://localhost:5560
Content-Type: application/json; charset=utf-8

{“ValorInformado”:”abc”}

Note que a requisição é realizada através da aplicação que está localizada no endereço http://localhost:5560, encaminhando-a para um serviço que encontra-se em um outro local, além desta, localizada no endereço http://localhost:5342. O grande detalhe a se notar na requisição é o header Origin, que é controlado pelo navegador, que o injeta na requisição. Já na resposta, o servidor analisa se aquele site solicitante (de qual partiu a requisição) possui ou não permissão para executar a requisição. Para indicar ao navegador que é permitido o acesso, basta retornar o endereço da aplicação que solicitou (ou * para qualquer uma) como valor do header Access-Control-Allow-Origin. Caso não informe nenhuma destas duas informações, a requisição não será concluída.

Requisições via GET com JSONP podem ser encaminhadas para outros servidores sem problemas; podemos também postar (POST) um formulário para um outro domínio. Em ambos os casos, não haveria necessidade de utilizar CORS. Qualquer outra requisição que diferencie destes critérios, deve utilizar o CORS para atingir o objetivo que queremos, e também exigirá uma cooperação por parte do servidor para conseguir executa-la.

Por exemplo, métodos como PUT ou DELETE, ou ainda, o envio de alguns headers ou de headers customizados, também podem ser controlados pelo servidor, pois será ele que definirá quais headers e/ou verbos que poderão ser acessíveis aos clientes. Para exemplificar, vamos supor que desejamos enviar um header customizado para o serviço, e ele deverá nos dizer se ele pode ou não ser encaminhado. Vamos analisar a imagem abaixo para ilustrar o comportamento deste outro cenário:

Note que agora temos duas requisições sendo realizadas ao servidor. A primeira é conhecida como preflight request, qual utiliza o método OPTIONS do HTTP, que tem a finalidade de extrair alguma informação a respeito da comunicação, e como já suspeitamos, vai trazer as informações necessárias para o navegador determinar se pode ou não ser executada. Vamos analisar a as requisições:

A primeira requisição encaminha ao servidor (1), além do Origin, mais dois headers: Access-Control-Request-Method e Access-Control-Request-Headers. O primeiro deles questiona o servidor se o cliente pode ou não executar um GET, enquanto o segundo questiona se o cliente pode ou não encaminhar os headers ali definidos. Na resposta para a requisição de OPTIONS, mais dois – novos – headers são devolvidos (2): Access-Control-Allow-Methods e Access-Control-Allow-Headers. O primeiro informa uma lista de métodos que são permitidos aquele cliente encaminhar; já o segundo, lista quais são os headers que podem ser encaminhados ao servidor. Depois de validado pelo navegador, a requisição efetiva é encaminhada para o servidor (3), qual retornará o conteúdo propriamento dito (4).

Como vimos, em duas etapas conseguimos realizar a comunicação entre domínios diferentes, com a possibilidade de refinar como ela deve ser executada. Como mencionei anteriormente, isso parece ser uma opção viável as técnicas que temos hoje para a comunicação entre domínios, e pelo que parece, há um grande empenho por parte dos fabricantes a adotá-lo. E, para finalizar, ainda é necessário que o servidor (serviço), saiba lidar com este tipo de requisição, que será tema para um outro post.

Habilitando JSONP no ASP.NET MVC

Recentemente mostrei aqui como devemos proceder para fazer uso do JSONP no WCF Web API, que permite o consumo de serviços através de domínios diferentes. Algumas vezes, quando já existe um projeto Web do tipo ASP.NET MVC, podemos expor uma ação no controller para que ele seja consumido diretamente pelo lado cliente da mesma (Javascript/jQuery), sem qualquer problema referente à chamada cross-domain.

Mas se quisermos expor isso para clientes que estão além do mesmo domínio, vamos nos deparar com os problemas que já conhecemos e/ou vimos anteriormente. A classe JsonResult, que já é parte do MVC, expõe um conteúdo baseado em JSON, mas não é capaz de envolver a resposta em uma função de callback (JSONP), algo que é necessário para que o jQuery/JSONP possa ser capaz de processar o resultado.

Temos várias alternativas para que isso funcione corretamente, e uma delas, seria criar um resultado customizado para capturar o nome da função de callback, que no caso do jQuery, é encaminhada através da querystring chamada callback, e por fim, envolvemos o resultado definido no interior da ação do controller nesta função, retornando o resultado conforme é esperado pelo jQuery. Abaixo temos o código que define um resultado de uma requisição via JSONP:

public class JsonpResult : JsonResult
{
    public override void ExecuteResult(ControllerContext context)
    {
        if (context == null)
            throw new ArgumentNullException(“context”);

        var callback = context.HttpContext.Request[“callback”];

        if (string.IsNullOrWhiteSpace(callback))
            throw new ArgumentNullException(“É necessário informar a função de callback”);

        if (this.Data != null)
            context.HttpContext.Response.Write(
                string.Format(“{0}({1});”,
                    callback, 
                    new JavaScriptSerializer().Serialize(this.Data)));
    }
}

Com este novo tipo criado, podemos simplesmente retornar uma instância desta classe, definido a propriedade Data (herdada da classe JsonResult) com o valor do objeto que queremos serializar, e o JsonpResult se encarregará de fazer o restante do trabalho, deixando o controller isento de qualquer código que interessa – somente – à infraestrutura.

public class ServicosController : Controller
{
    public ActionResult ViaGet(string valor)
    {
        return new JsonpResult() { Data = new { ValorInformado = “bla bla bla” } };
    }
}

O impacto do limitador de conexões HTTP

Internamente o .NET Framework possui uma classe chamada ServicePoint que controla as conexões HTTP que são realizadas. A sua criação é feita e gerenciada por uma outra classe, chamada de ServicePointManager, e ambas estão debaixo do namespace System.Net. A criação não se dá de forma desordenada, ou seja, ela é criada para atender um determinado recurso (página, serviço, imagem, etc.), e ao invés de desprezá-la, ela é armazenada e compartilhada para quando precisarmos, novamente, acessar aquele mesmo servidor.

Para falarmos de classes de mais alto nível, um exemplo é a classe HttpWebRequest que utilizamos para realizar requisições HTTP, que recorre internamente à classe ServicePointManager, e que por sua vez, faz todas verificações necessárias, e devolve um objeto ServicePoint pronto para ser utilizado. Como há uma única instância desta classe com aquele servidor, podemos ter a necessidade de realizar conexões simultâneas para ele. Por questões de performance, a especificação do protocolo HTTP determina que um cliente não deve manter mais do que duas conexões com um mesmo servidor.

Apesar desta sugestão, podemos ter a necessidade de aumentar esse valor para que possamos executar mais requisições concorrentes a um mesmo servidor. Pensando nisso, a Microsoft disponibiliza um configuração global, qual nos permite determinar a quantidade de conexões concorrentes que podemos realizar à um mesmo servidor. Para isso, há várias propriedades estáticas, que estão expostas a partir da classe ServicePointManager, e a propriedade que controla a quantidade de conexões é a DefaultConnectionLimit, onde o padrão é apenas 2 conexões, assim como sugere o HTTP/1.1.

Quando consumimos serviços WCF ou até mesmo serviços do tipo ASMX, não lidamos – diretamente – com as classes que vimos aqui, mas se analisarmos os bastidores das classes do WCF (ClientBase<TChannel>) e do ASMX (SoapHttpClientProtocol), veremos que eles, em algum momento, vai recorrer à classe HttpWebRequest e, consequentemente, estaremos sendo limitados caso haja a necessidade de realizar mais do que duas conexões concorrentes ao mesmo servidor.

Supondo que temos um serviço WCF e queremos consumí-lo em uma aplicação cliente, e para efeito dos testes, vamos criar 100 requisições concorrentes para o mesmo. Um pequeno detalhe, é que já definimos a quantidade mínima de threads para que o ThreadPool já as crie, nos antecipando e dizendo a ele quantas threads serão necessárias para executarmos o trabalho.

const int QtdeDeRequisicoes = 100;

ServicePointManager.DefaultConnectionLimit = 2;
ThreadPool.SetMinThreads(QtdeDeRequisicoes, QtdeDeRequisicoes);

var tasks = new Task[QtdeDeRequisicoes];
var sw = Stopwatch.StartNew();

for (int i = 0; i < QtdeDeRequisicoes; i++)
{
    tasks[i] =
        Task.Factory.StartNew<string>(o =>
        {
            Console.WriteLine(“Inicio:t” + o);

            using (var proxy = new ServiceReference1.ServiceClient())
                return proxy.GetData((int)o);
        }, i)
        .ContinueWith(t => Console.WriteLine(“Fim:t” + t.Result));
}

Task.WaitAll(tasks);
Console.WriteLine(sw.Elapsed);

Note que no código acima estamos explicitamente definindo que a aplicação cliente pode somente estabelecer duas conexões concorrentes com um mesmo servidor. Para o serviço de teste, ele levará, na minha máquina, cerca de 48 segundos. O gráfico abaixo ilustra a execução destas requisições. Enquanto a linha vermelha mostra a quantidade de requisições que chegaram até o serviço, a linha verde exibe a quantidade de requisições que estão sendo executadas por ele. Tudo isso sendo extraído do servidor onde o mesmo está hospedado.

Se mudarmos ligeiramente o código acima, definindo para 15 a propriedade DefaultConnectionLimit, o tempo para executar as mesmas 100 requisições cai para 20 segundos, ou seja, temos um ganho considerável. Novamente, através do gráfico abaixo temos as mesmas requisições em um tempo bem mais reduzido:

Observação: Apesar de facilitar a vida do cliente, esta configuração poderá comprometer o desempenho do serviço/servidor, pois estamos atendendo várias requisições que partem de um mesmo cliente, exacerbando o serviço com requisições que poderiam estar distribuídas entre outros interessados em consumir este mesmo serviço.

É importante mencionar que o cliente criado para consumir o serviço WCF de exemplo, é uma aplicação Windows (Console). Quando a aplicação cliente é uma aplicação Web (ASP.NET), também podemos ser influenciado por esta configuração, mas neste caso, ele está dimensionado de uma forma diferente, ou seja, em sua configuração padrão, no interior da classe HttpRuntime, ele define a propriedade DefaultConnectionLimit como 12 * quantidade de CPUs da máquina atual. Sendo assim, qualquer conexão HTTP que você realize através desta aplicação Web, você estará “limitado” à esta quantidade de conexões.

Finalmente, para efeito de testes, você não pode ter o cliente e o serviço na mesma máquina, pois a classe ServicePointManager avalia se o serviço está hospedado localmente, e se estiver, retorna a constante Int32.MaxValue (2147483647) como quantidade de conexões simultâneas, sendo um valor que dificilmente será atingido.

WCF Web API – Suporte à JSONP

Uma das grandes necessidades no consumo de serviços por parte das aplicações Web, é consumir serviços criados e que estão além da própria aplicação cliente, que provavelmente estará debaixo de um outro domínio, e por questões de segurança, isso não será permitido diretamente, já que se utilizado de forma maliciosa e sem o consentimento do usuário, pode por em risco as informações e a navegação dos usuários.

Para contornar essa “limitação”, então precisamos de alguma técnica para possibilitar que essa tarefa seja realizada. Uma opção seria a criação de um serviço nesta aplicação cliente, que serviria como um wrapper, e este por sua vez, consumiria diretamente o serviço, sem as imposições de chamada entre domínios que o navegador impõe. Com isso, o código JavaScript irá consumir este serviço local, que por sua vez, encaminharia a requisição para o serviço remoto, em outro domínio.

Apesar desta técnica funcionar, ela acaba sendo uma solução ruim, já que teremos que envolver outros elementos para realizar uma tarefa relativamente simples. Felizmente o jQuery fornece nativamente o suporte a uma técnica conhecida como JSONP (JSON with Padding).

O seu funcionamento não é muito complicado. Como disse acima, requisições entre domínios não são permitidas, mas há uma única exceção: a tag , ou seja, podemos definir no elemento src (source) a URL para um recurso que está além do nosso domínio, que o navegador não irá proibir o acesso. O que o JSONP faz é justamente o uso dela, criando dinamicamente esta tag, e definindo no atributo src a URL do serviço que estamos tentando acessar.

Na verdade isso não funciona sozinho, ou seja, precisa de uma certa colaboração por parte do serviço, para que o cliente possa processar o resultado da forma correta. Além dos parâmetros que são exigidos pelo método do serviço, o jQuery inclui um parâmetro chamado callback, que é o nome de uma função criada temporariamente no cliente. Aqui entra em cena a infraestrutura do serviço, que deve ser capaz de retornar o resultado (dados) envolvido nesta função, e quando o mesmo chegar ao cliente, ele invocará para capturar o resultado e encaminhá-lo para o nosso código, e assim iremos manipular da forma que acharmos mais conveniente. Falaremos da implementação por parte do serviço mais tarde.

Para fazer tudo isso funcionar, precisamos nos atentar à alguns detalhes do lado do cliente e do lado do serviço. Do lado do cliente, tudo o que precisamos fazer é indicar para a API de AJAX do jQuery que ela deve utilizar JSONP. Para isso, devemos recorrer ao atributo dataType, que indica o tipo de dado/formato que você está esperando que o servidor te retorne. No nosso caso, vamos apontar jsonp, assim como é mostrado no código abaixo:

    $(document).ready(function () {
        $.ajax(
        {
            type: ‘GET’,
            url: ‘http://ipv4.fiddler:1191/cotacoes&#8217;,
            dataType: ‘jsonp’,
            success: function (cotacoes) {
                var itens = [];

                $.each(cotacoes, function (indice, cotacao) {
                    itens.push(‘

  • ‘ + cotacao.Moeda + ‘: ‘ + cotacao.ValorEmReal + ‘
  • ‘);
                    });

                    $(‘

      ‘, { html: itens.join(”) }).appendTo($(‘#Cotacoes’));
              }
          });
      });

      </head>
      <body>
         

         

      </body>
      </html>

      Por parte do cliente, o jQuery fornece parâmetros para realizarmos a configuração via JSONP. Como podemos perceber no código acima, em negrito temos do tipo da requisição sendo definido como JSONP, o que faz com que a requisição seja formatada da seguinte forma (repare o que temos em negrito):

      GET http://127.0.0.1:1191/cotacoes?callback=jQuery15109440240194135102_1328569080908&_=1328569080915 HTTP/1.1
      Accept: application/javascript, */*;q=0.8
      Referer: http://ipv4.fiddler:1185/Index.htm
      Accept-Language: en-US,pt-BR;q=0.5
      User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
      Accept-Encoding: gzip, deflate
      Host: 127.0.0.1:1191
      Connection: Keep-Alive

      Como disse acima, é necessário que o serviço também de suporte à esta funcionalidade. A versão atual do WCF Web API, que está na 0.6, já traz esse recurso nativamente, e com poucas (talvez nenhuma) configurações, podemos construir e expor o serviço para que ele seja consumido através de um cliente que esteja hospedado em um outro domínio. Para o exemplo, temos um serviço “dummy” de cotação de câmbio, que possui os dados estáticos. Apenas como observação, não é mais necessário que o serviço seja decorado com o atributo ServiceContractAttribute.

      public class ServicoDeCotacoes
      {
          [WebGet]
          public IEnumerable<Cotacao> RecuperarCotacoes()
          {
              return new[]
              { 
                  new Cotacao() { Moeda = “Dólar Americano”, ValorEmReal = 1.7263M },
                  new Cotacao() { Moeda = “Euro”, ValorEmReal = 2.2653M },
                  new Cotacao() { Moeda = “Libra”, ValorEmReal = 2.7308M }
              };
          }
      }

      Finalmente, tudo o que precisamos fazer com o serviço é configurá-lo através da classe WebApiConfiguration, algo como já era realizado nas versões anteriores desta API. Abaixo temos um código simples, que ilustra como procedemos para realizar tal configuração:

      public class MvcApplication : System.Web.HttpApplication
      {
          protected void Application_Start()
          {
              ConfigurarServico();
          }

          private static void ConfigurarServico()
          {
              RouteTable.Routes.MapServiceRoute<ServicoDeCotacoes>(
                  “cotacoes”,
                  new WebApiConfiguration()
                  {
                      CreateInstance = (t, ic, msg) => new ServicoDeCotacoes()
                  });
          }
      }

      Ao executar a requisição para o serviço e interceptando-a, teremos na resposta da mesma, a função criada dinamicamente no cliente que será executada automaticamente pelo próprio jQuery. Mais uma vez, repare o que temos negritado abaixo. Note que o nome da função que foi criado pelo jQuery e repassado para o serviço, é devolvido para o mesmo.

      HTTP/1.1 200 OK
      Server: ASP.NET Development Server/10.0.0.0
      Date: Mon, 06 Feb 2012 22:58:00 GMT
      X-AspNet-Version: 4.0.30319
      jsonp-callback: jQuery15109440240194135102_1328569080908
      Content-Length: 170
      Cache-Control: private
      Content-Type: application/javascript; charset=utf-8
      Connection: Close

      jQuery15109440240194135102_1328569080908([{“Moeda”:”Dólar Americano”,”ValorEmReal”:1.7263},{“Moeda”:”Euro”,”ValorEmReal”:2.2653},{“Moeda”:”Libra”,”ValorEmReal”:2.7308}])

      Nenhuma configuração extra foi realizada por parte do serviço, porque a Microsoft entende que isso seja uma necessidade comum, o que faz com que já venha devidamente configurado. Internamente temos um operation response handler chamado JsonpHttpResponseHandler, que é responsável por avaliar se a requisição é ou não uma requisição do tipo JSONP, e para isso, verifica se há uma querystring chamada callback. Caso queira alterar o nome desta querystring, pode-se recorrer à propriedade CallbackQueryParameter deste próprio handler.

      Além disso, ainda temos um media type customizado, chamado de JsonpMediaTypeFormatter, que envolve o resultado gerado pelo serviço, pela função (callback) criada pelo jQuery, que entenderá isso como o resultado que será repassado para a função de sucesso, configurada na chamada do método $.ajax.