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

Stacks de Comunicação do Silverlight

Como sabemos, aplicações Silverlight rodam no cliente, dentro do seu navegador, ou mais recentemente, também temos a possibilidade de desacoplar a aplicação do mesmo, dando a impressão ao usuário de que é uma aplicação que roda localmente. O fato da aplicação rodar “desconectada” do servidor, havia uma grande necessidade de expor funcionalidades e dados para ela, e o WCF eleito como a “ponte” entre os dois lados, para estabelecer a comunicação, permitindo com que as aplicações cheguem até a sua origem e executem alguma tarefa ou extraiam dados necessários para que elas possam trabalhar.

Desde as primeiras versões do Silverlight que temos APIs dentro dele para comunicação HTTP e a API do WCF (System.ServiceModel.dll), para abstrair toda a complexidade de consumir um serviço SOAP. Essas APIs recorrem aos recursos expostos pelo navegador, estando assim condicionadas as suas limitações. Apesar de algumas dessas limitações, como era o caso da propagação de erros do serviço para o cliente, gerenciamento de cookies e chamada concorrente para serviços, essas APIs funcionavam razoavelmente bem. Mas a questão é que os serviços tem evoluído cada vez mais, obrigando a Microsoft a melhorar o modelo de comunicação dentro do Silverlight.

O que tínhamos até a versão 2.0 é o que chamamos de Browser Http Stack. Com ela, conseguíamos efetuar comunicações com serviços, mas com algumas limitações, pois estávamos condicionados aos recursos que o navegador oferecia, afinal, ela é apenas um wrapper para ele. Além de não conseguir interpretar um erro SOAP corretamente, uma outra limitação é a possibilidade de executar serviços além dos tradicionais verbos POST e GET do protocolo HTTP. Como serviços REST estão cada vez mais populares, existe uma grande necessidade de suportar mais do que estes dois verbos.

Para resolver estes tipos de problemas, e tentar acomodar novas funcionalidades, a Microsoft incluiu na versão 3.0 do Silverlight, uma nova forma de comunicação, chamada de Client Http Stack. A palavra “Client” é porque agora a comunicação utiliza os recursos fornecidos pelo sistema operacional, burlando as limitações impostas pelo navegador. Além de resolver os problemas que vimos acima, ela permite interpretar todos os headers, melhor forma de manipular cookies, códigos de status das respostas, algumas melhorias na parte de autenticação, etc.

Uma das preocupações da Microsoft foi em manter a modelo de utilização das classes que você já utiliza para efetuar a comunicação com algum desses serviços, podendo alterar entre uma das stacks, sem precisar mudar algo no código que faz o consumo do serviço.

Por padrão o Silverlight continua utilizando o modelo tradicional (Browser Http Stack), e se você quiser utilizar o Client Http Stack, terá que explicitamente dizer isso à ele. Para isso, devemos utilizar o método estático RegisterPrefix da classe WebRequest (namespace System.Net). O primeiro parâmetro consiste na URI (http://www.site.com.br) ou apenas o prefixo (http ou https) para onde quer se comunicar. Já o segundo parâmetro indica qual dos modelos utilizar (Browser ou Client). Esse método retorna um valor boleano, indicando se o registro foi ou não realizado com sucesso. O código abaixo ilustra como podemos proceder para efetuarmos essa configuração:

WebRequest.RegisterPrefix(“http://&#8221;, WebRequestCreator.ClientHttp);

Caso queira retornar a configuração padrão, então poderá utilizar a propriedade estática BrowserHttp, também exposta pela classe WebRequestCreator, assim como é exibida abaixo:

WebRequest.RegisterPrefix(“http://&#8221;, WebRequestCreator.BrowserHttp);

Comunicação Local no Silverlight

Como sabemos, podemos consumir serviços WCF em aplicações Silverlight. Isso nos permite colocar alguma tarefa em um serviço na aplicação que faz a hospedagem do serviço ou até mesmo em outros locais, fora do domínio qual ela se encontra. A ideia aqui é permitir a comunicação entre a aplicação Silverlight (que roda dentro do navegador) e serviços que estão hospedados além dessa máquina.

Mas e se precisarmos de algo mais simples, como por exemplo, a comunicação entre duas aplicações Silverlight que rodam dentro do navegador em uma mesma máquina? Utilizar o WCF aqui pode ser extremamente complicado, pois exigirá desenvolvermos uma série de funcionalidades para permitir esse interação, e ainda podemos ter um grande overhead, já que a comunicação não será local e dependerá de que a conexão esteja disponível com o servidor/serviço com qual queremos dialogar.

Para esse tipo de cenário o Silverlight fornece algo bem mais simples de se trabalhar, que é uma funcionalidade conhecida como “comunicação local”. A ideia aqui é criar aplicações que geram informações, e aquelas que estiverem interessadas, podem capturá-las e tratar da forma que achar mais conveniente. Esse tipo de comunicação pode ser utilizada por plugins que rodam dentro da mesma página, em páginas diferentes, estando ou não dentro do mesmo domínio.

Através das imagens abaixo podemos analisar os cenários mais comuns. Na primeira imagem (1) temos uma única página ASPX hospedando duas aplicações Silverlight, e se precisarmos efetuar a comunicação entre elas, podemos utilizar o recurso que veremos aqui. Já na segunda imagem (2), temos duas página distintas dentro de um mesmo domínio, mas cada página hospeda uma aplicação Silverlight diferente, e da mesma forma, a comunicação também será possível. Na terceira (3) e última imagem, temos duas aplicações, mas cada uma delas está hospedada em um domínio diferente, mas isso também pode ser permitido, mas falaremos mais disso abaixo.

A implementação é relativamente simples. Para utilizarmos a comunicação local entre aplicações Silverlight, vamos recorrer aos tipos que estão disponível a partir do namespace System.Windows.Messaging. As principais classes que teremos aqui são: LocalMessageSender e LocalMenssageReceiver. Como podemos perceber, a primeira classe é responsável por enviar mensagens, enquanto a segunda se encarrega de receber tais mensagens.

Aqui é importante comentarmos sobre algumas “limitações”: tudo o que podemos mandar de um lado à outro deve ser, obrigatoriamente, uma string. Qualquer coisa diferente disso, exigirá um trabalho extra, como serializar o objeto em algum formato Xml ou Json. Dependendo da quantidade de informação que você levar de um lado para outro, considere o uso do Json ao invés do Xml, que é bem menos verboso, e isso pode evitar você atingir o limite máximo do tamanho da string, que deve ser menor ou igual a 40KB. Uma outra alternativa aqui é serializar as informações em formato binário e utilizar Base64 para codificá-la.

Se vamos gerar uma aplicação que gera informações, então temos que recorrer ao uso da classe LocalMessageSender. Em seu construtor ela recebe uma string que corresponde ao nome do destinatário das mensagens geradas por ela. Já o segundo parâmetro do construtor desta classe, recebe uma string contendo o domínio que receberá as mensagens. Você pode utilizar o membro estático chamado Global desta mesma classe, que corresponde à um “*”, e instrui o Silverlight que qualquer domínio poderá receber as mensagens. Finalmente, essa mesma classe fornece o método chamado SendAsync, que permite o envio de uma string para aqueles que desejarem capturá-la.

Chega o momento de efetuar a configuração do destinatário. Agora entra em cena a classe LocalMessageReceiver, que recebe em seu construtor três parâmetros: uma string com o nome do destinatário, uma das opções do enumerador ReceiverNameScope e, finalmente, uma coleção de strings, que representa os domínios de quais a aplicação poderá receber mensagens. Essa classe fornece um evento chamado MessageReceived, que é disparado quando uma nova mensagem chega para a aplicação, e para capturá-la, tudo o que precisamos fazer é nos vincularmos a este evento e acessar a mensagem através da propriedade Message do argumento MessageReceivedEventArgs. Para finalizar, o método Listen é responsável por começar a monitorar as mensagens que chegam e entregá-las para o evento acima.

Depois de conhecer essas classes, podemos já fazer o uso delas nas nossas aplicações. Para exemplificar, teremos duas aplicações Silverlight, hospedadas em locais diferentes. A ideia será permitir a comunicação entre elas, e para manter a simplicidade do exemplo, tudo o que a aplicação fará ao receber a mensagem, será colocá-la em um TextBox. Abaixo temos a configuração de uma das aplicações, utilizando tudo o que vimos acima:

public partial class MainPage : UserControl
{
    private LocalMessageSender sender;
    private LocalMessageReceiver receiver;

    public MainPage(string aplicacaoLocal, string aplicacaoRemota)
    {
        InitializeComponent();

        this.sender = new LocalMessageSender(aplicacaoRemota, LocalMessageSender.Global);
        this.receiver = new LocalMessageReceiver(
            aplicacaoLocal, ReceiverNameScope.Global, LocalMessageReceiver.AnyDomain);

        this.receiver.MessageReceived += 
            new EventHandler<MessageReceivedEventArgs>(receiver_MessageReceived);
        this.receiver.Listen();
    }

    private void receiver_MessageReceived(object sender, MessageReceivedEventArgs e)
    {
        this.Mensagens.Text += string.Format(“{0}{1}”, e.Message, Environment.NewLine);
    }

    private void EnviaMensagem_Click(object sender, RoutedEventArgs e)
    {
        this.sender.SendAsync(this.Mensagem.Text);
    }
}

O código da outra aplicação será exatamente igual. O único detalhe ali é o construtor da classe MainPage, que recebe como parâmetros o nome local e o nome remoto. O nome remoto é utilizado no construtor da classe LocalMessageSender, pois quero enviar mensagens para este destino. Já o nome local é utilizado pelo LocalMessageReceiver, que é de onde estou interessado em receber mensagens. Mais detalhes sobre estes parâmetros na próxima seção do artigo.

Com isso em funcionamento, ao rodar as aplicações já podemos perceber o resultado. Através da imagem abaixo, vemos que o conteúdo do TextBox da aplicação 01 foi para a aplicação 02 e vice-versa.

Parametrizando as Aplicações

Acima pudemos perceber que a classe que corresponde ao controle do Silverlight (MainPage), foi parametrizada com as duas informações, que correspondem de onde a aplicação quer receber e para onde ela quer enviar informações. Esses nomes não precisam, necessariamente, corresponder a nome de aplicações. A ideia é ter um nome coerente com o tipo de informação que está sendo gerada.

Outro detalhe importante é com relação ao nome que você define para o recebedor das mensagens, pois podemos ter a mesma aplicação carregada em outra instância do navegador, e ao definir o mesmo nome, uma exceção do tipo ListenFailedException será disparada para informar que já existe um recebedor registrado com este mesmo nome.

Para evitar isso, utilizaremos a “ponte” que existe entre o Silverlight e o código HTML que o hospeda. Isso permitirá gerarmos um valor randômico via Javascript e definir na inicialização do plugin, que será encaminhada para aqueles parâmetros que vimos no construtor da classe MainPage. Para que isso funcione, temos que adicionar um novo elemento <param /> na tag object que hospeda a aplicação Silverlight (*.xap), e nomear este parâmetro como initParams. O código abaixo ilustra a adição deste novo parâmetro, com algumas informações suprimidas por questões de espaço.

   
            name=”initParams”
        value=”AplicacaoLocal=Aplicacao01,AplicacaoRemota=Aplicacao02″ />
   

A configuração refere-se à aplicação 01. Para a aplicação 02, esses parâmetros estão invertidos, já que terão papéis diferentes.

Com isso, o valor colocado ali será entregue em formato de um dicionário ao evento Startup da classe Application, que estará acessível através do arquivo App.xaml. É neste momento que extraímos os parâmetros deste dicionário e preenchemos o construtor da classe MainPage, assim como podemos notar através do código abaixo:

private void Application_Startup(object sender, StartupEventArgs e)
{
    this.RootVisual = 
        new MainPage(e.InitParams[“AplicacaoLocal”], e.InitParams[“AplicacaoRemota”]);
}

Conclusão: Neste artigo vimos a utilização de uma técnica interessante que nos permite a comuicação local (no mesmo computador) de aplicações Silverlight. Podemos utilizar esse recurso para cada vez mais criar aplicações independentes, e se mais tarde, precisarmos de interação entre elas, podemos recorrer à este recurso simples, mas que traz um grande poder as mesmas.

ComunicaoLocalSL.zip (144.66 kb)

Autenticação com WCF e jQuery

Recentemente escrevi sobre o consumo de serviços WCF a partir do jQuery. Naquele artigo foi comentado como construir serviços WCF para ser acessados através do ambiente REST, e além disso, vimos também como proceder para o consumo deste serviço utilizando o jQuery como cliente.

Mas um detalhe que não foi abordado no artigo foi a questão da segurança, ou melhor, do processo de autenticação do cliente que consome o serviço. Por exemplo, imagine que temos um serviço que exige que o usuário se identifique, para que assim possamos determinar se ele terá ou não acesso ao serviço. Apesar do WCF fornecer várias alternativas para isso, quando estamos em um ambiente REST, alguns cuidados especiais são necessários, quais serão abordados no decorrer deste artigo.

O primeiro detalhe para nos atentarmos é como vamos configurar o serviço para que o mesmo possa exigir as credenciais. Para expor um serviço para ser consumido através do ambiente REST, utilizamos um binding exclusivo chamado de WebHttpBinding. Em sua configuração padrão, não há nenhum tipo de autenticação configurada, mas como qualquer binding, podemos recorrer à opção security para isso.

Temos apenas três opções relacionadas à segurança para este binding: None, Transport e TransportCredentialOnly. A primeira opção desabilita qualquer tipo de proteção e autenticação no respectivo serviço. Já a segunda opção, Transport, determina que será o protocolo que deverá garantir a segurança da mensagem (HTTPS) e, finalmente, o TransportCredentialOnly, que não fornecerá integridade e confidencialidade na mensagem que está sendo trafegada, e utilizará apenas o protocolo HTTP exclusivamente para autenticação do usuário.

Depois desta configuração que determina como a comunicação deverá ser protegida, temos uma espécie de “sub-configuração” dela que precisamos nos atentar. Esta sub-configuração determina como as credenciais serão passadas para o serviço. Entre as várias formas, temos o HTTP Basic, que faz com que as credenciais viagem do cliente para o serviço sem qualquer espécie de criptografia. Esse modelo, em sua configuração padrão, tem uma forte afinidade com o Windows/Active Directory, ou seja, para utilizar esse recurso, as credenciais informadas do lado do cliente deverão refletir uma conta válida no Windows/Active Directory, algo que não vamos nos preocupar neste momento. A configuração do serviço WCF deverá ficar da seguinte forma:

<system.serviceModel>
  <services>
    <service
      name=”RESTComBasicAuthentication.Services.ServicoDeUsuarios”
      behaviorConfiguration=”config”>
      <endpoint
        address=””
        binding=”webHttpBinding”
        contract=”RESTComBasicAuthentication.Services.IUsuarios”
        behaviorConfiguration=”edpConfig”
        bindingConfiguration=”bc” />
    </service>
  </services>
  <bindings>
    <webHttpBinding>
      <binding name=”bc”>
        <security mode=”TransportCredentialOnly”>
          <transport clientCredentialType=”Basic” />
        </security>
      </binding>
    </webHttpBinding>
  </bindings>
  <!– Outras Configurações –>
</system.serviceModel>

Quando utilizamos o modelo Basic, ao tentar acessar um recurso protegido, o próprio browser é capaz de identificar e abrir uma janela com os campos para informarmos o username e password, só que não podemos nos esquecer de que esse serviço será consumido por algum cliente, e que o foco aqui é o uso do jQuery, e com isso, de alguma forma precisamos enviar o username e password do cliente para o serviço. Como já sabemos, o jQuery oferece uma função chamada $.ajax, que nos permite configurar e efetuar a chamada para um determinado serviço ou algum outro método. Internamente, este método recorre a um objeto popularmente conhecido, que é o XMLHttpRequest. Este objeto é o responsável por gerenciar toda a comunicação entre o cliente e o serviço.

De acordo com a especificação deste objeto, há um método chamado Open, que entre os parâmetros convencionais, como endereço até o serviço, o tipo da requisição (Json ou Xml), há também como informar mais duas informações relacionadas ao processo de autenticação: username e password. Através dos parâmetros username e password, definimos duas strings que representam cada uma dessas informações. Como o jQuery abstrai o acesso a este objeto, a função $.ajax também nos permite informar o usuário e senha, como já mencionado acima. Sabendo da existência destes parâmetros, podemos configurar a chamada para o serviço através do jQuery da seguinte forma:

function RecuperarUsuario() {
    $.ajax(
    {
        type: “POST”,
        username: “UsuarioQueExisteNoWindows”,
        password: “123456”,
        url: “http://localhost/Services/ServicoDeUsuarios.svc/RecuperarUsuario&#8221;,
        contentType: “application/json”,
        data: ‘{ “nome”: “Israel Aece”, “email”: “ia@israelaece.com” }’,
        processData: true,
        success:
            function (resultado) {
                alert(resultado.RecuperarUsuarioResult.Nome);
                alert(resultado.RecuperarUsuarioResult.Email);
            },
    });
}

Se você monitorar a requisição para este serviço com alguma ferramenta, como é o caso do Fiddler, você verá que o username e password não serão enviados até que realmente seja necessário. O modelo de autenticação Basic é baseado no processo conhecido como “Desafio HTTP 401”, que funciona da seguinte forma:

  • O cliente solicita um recurso (página, serviço, etc.) que está protegido.
  • Ao detectar que o cliente não 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 código 401 (Access Denied), que instrui o cliente (browser) a solicitar as credenciais de acesso.
  • Uma vez informado, o browser recria a mesma requisição, mas agora envia nos headers da mesma o usernamepassword codificados em Base64, sem qualquer espécie 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 usuário válido, permitirá o acesso, caso contrário retornará a mesma resposta com código 401, até que ele digite uma credencial válida.

Apesar das credenciais estarem em hard-code no exemplo acima, nada impede de criarmos uma tela onde o cliente pode digitar um usuário e senha, mas lembrando que este usuário deverá exisitir no Windows/Active Directory.

Customização

O principal ponto negativo da solução acima é a necessidade de termos os usuários cadastrados no Windows, algo que pode ser inviável em um ambiente que não é controlado, como é o caso da internet. Algo muito comum em aplicações deste tipo, é a validação do usuário em uma base de dados, ou até mesmo, utilizando a estrutura do Membership do ASP.NET. Para atingirmos esse objetivo, precisamos entender um pouco mais sobre o processo de autenticação e também alguns pontos de estensibilidade.

Quando configuramos o modelo Basic, o IIS é o responsável por coordenar todo o processo de acesso ao recurso, e se o usuário não estiver autenticado, o próprio IIS devolve a mensagem com o código 401 e o header específico para o mesmo (1), para que o browser proceda com a solicitação das credenciais (2), e depois de informadas, refaz a requisição embutindo o header com as credencias codificadas (3). A imagem abaixo ilustra esse processo:

No exemplo que vimos acima, o único recurso protegido pelo modelo Basic é apenas o arquivo ServicoDeUsuarios.svc. Agora, se desejamos customizar, temos que trazer todo o controle do processo de autenticação para a aplicação, ou seja, não iremos mais querer que o IIS coordene o processo, que como sabemos, ele recorre ao Windows para validar os usuários. Sendo assim, precisamos permitir o acesso anônimo ao arquivo *.svc.

Há algum tempo eu comentei sobre a possibilidade de efetuar a customização da autenticação do WCF através de usuário e senha, utilizando a classe UserNamePasswordValidator para essa validação. O problema é que o binding WebHttpBinding não suporta a customização deste validador, o que nos obrigaria à descer o nível até o pipeline do ASP.NET para implementar algo específico para o WCF.

Ao invés disso, podemos recorrer aos interceptadores (Interceptors). Os interceptadores não estão nativamente dentro do WCF, mas estão disponíveis ao instalar o WCF-REST Starter Kit. Este kit nada mais é que um conjunto de funcionalidades que podemos incorporar aos nossos projetos WCF baseados em REST, tornando algumas tarefas comuns em algo mais simples de se resolver/implementar, como vai ser o caso aqui.

Ao instalar este kit, teremos à nossa disposição alguns novos assemblies, e entre eles um chamado Microsoft.ServiceModel.Web.dll. Uma das classes fornecidas por ele é a classe abstrata RequestInterceptor. Essa classe fornece um método abstrato chamado ProcessRequest, que permite interceptar a requisição, antes mesmo dela começar a ser executada, fornecendo um parâmetro do tipo RequestContext, que representa o contexto da requisição atual, qual será utilizado para a interação com o cliente que está tentando acessar o recurso.

Com esta possibilidade, podemos criar um interceptador que extrai o header da requisição HTTP que representa a credencial informada pelo usuário (WWW-Authenticate), e a valida em algum repositório de sua escolha, como uma base de dados. A partir daqui é necessário conhecermos como funciona o processo do modelo HTTP Basic, para conseguirmos dialogar com o cliente, para que assim ele consiga coordenar o processo de autenticação do usuário.

Como havia dito acima, o username e password não são enviados até que sejam efetivamente exigidos. Nesta customização, ao identificarmos que o header não está presente na requisição, precisamos configurar a resposta para o cliente com o código 401, que representa acesso não autorizado, e informar na resposta o mesmo header, para continuar obrigando o usuário a informar o username e password.

Para saber se o cliente informou as credenciais, precisamos detectar a presença do header chamado Authorization. Se existir, então precisamos decodificá-lo, utilizando o método 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 validação em algum repositório. O código abaixo ilustra esse processo:

string credentials = mp.Headers[“Authorization”];

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

    int separator = decodedCredentials.IndexOf(‘:’);
    username = decodedCredentials.Substring(0, separator);
    password = decodedCredentials.Substring(separator + 1);
}

Caso o header não exista ou o usuário não existir na base de dados, então podemos criar o header para que o cliente seja – novamente – obrigado a informar as credenciais. Para isso, utilizamos as propriedades da mensagem, e configuramos a mensagem de retorno. A mensagem é representada no WCF pela classe Message. O código abaixo ilustra a criação, configuração e resposta ao cliente com esta mensagem recém criada:

private void GenerateAccessDeniedMessage(ref RequestContext requestContext)
{
    Message reply = Message.CreateMessage(MessageVersion.None, null, null
        new DataContractJsonSerializer(typeof(object)));

    HttpResponseMessageProperty hrp = new HttpResponseMessageProperty();
    hrp.StatusCode = HttpStatusCode.Unauthorized;
    hrp.Headers.Add(“WWW-Authenticate”, string.Format(“Basic realm=”{0}””, this.Realm));
    reply.Properties[HttpResponseMessageProperty.Name] = hrp;

    requestContext.Reply(reply);
    requestContext = null;
}

Se o usuário for válido, então é necessário inicializar o contexto de segurança do WCF, que é representado pela classe ServiceSecurityContext, que utiliza uma instância da classe GenericPrincipal para identificar o usuário logado.

Finalmente, tudo isso não funciona por si só. Ainda precisamos acoplar a instância desta classe à execução. Para isso, devemos recorrer a customização da classe que cria o host, que é responsável por gerenciar a execução da classe que representa o serviço. A classe ServiceHostFactory fornece um método chamado CreateServiceHost, que como o próprio nome diz, permite retornar qualquer classe que herde direta ou indiretamente da classe ServiceHost. Dentro do assembly do WCF-Rest Starter Kit, temos uma versão específica de host, chamada de WebServiceHost2. A grande diferença deste host, é que ele expõe uma propriedade chamada Interceptors, que permite adicionarmos qualquer interceptador, desde que ele herde da classe RequestInterceptor, como já vimos acima. Depois que a factory customizada foi criada, devemos alterar o arquivo *.svc para que ela seja utilizada:

<%@ ServiceHost
    Language=”C#”
    Debug=”true”
    Factory=”RESTComBasicAuthentication.CustomRestHostFactory”
    Service=”RESTComBasicAuthentication.Services.ServicoDeUsuarios”
    CodeBehind=”ServicoDeUsuarios.svc.cs” %>

Uma vez que acoplamos este interceptador, ele é quem gerenciará o processo de autenticação, ou seja, o cliente irá dialogar com este interceptador, mas para que isso funcione corretamente, é necessário que a autenticação Basic esteja desabilitada no IIS. Através da imagem abaixo, podemos reparar este novo comportamento:

Conclusão: Apesar de não temos nativamente no WCF uma forma de customizar a autenticação em serviços REST, podemos recorrer ao WCF-REST Starter Kit para conseguir efetuar essa customização, utilizando a infraestrutura oferecida pelo modelo HTTP Basic para enviar as credenciais. Apesar de tudo funcionar como deveria, é importante dizer que os dados continuam sendo trafegados sem qualquer proteção, e para evitar que alguém visualize o conteúdo, é importante que toda a comunicação seja protegida pelo HTTPS.

RESTComBasicAuthentication.zip (328.00 kb)

Codificando.NET 2010 – Palestra sobre WCF

No próximo dia 19 de junho (sábado), acontecerá em São Paulo um evento chamado Codificando 2010, organizado pela comunidade Codificando.NET. Esse evento terá várias sessões focadas exclusivamente em desenvolvimento de aplicações utilizando a plataforma .NET, com especialistas de mercado. Para maiores detalhes sobre o evento em geral, consulte o site neste endereço.

Eu fui convidado pelo Alexandre Tarifa para falar sobre WCF – Windows Communication Foundation, que é a alternativa no ambiente Microsoft/.NET para construção de aplicações distribuídas e conectadas. É importante dizer que a palestra será de nível 100, abordando superficialmente algumas das principais funcionalidades e mudanças que aconteceram nesta nova versão da tecnologia, permitindo desmistificar os principais elementos que compõem a estrutura do WCF. Abaixo temos a descrição da palestra:

Título: Distribuindo Componentes com WCF
Palestrante: Israel Aece
Descritivo: O WCF é o pilar de comunicação da plataforma .NET, e que está presente desde a versão 3.0. Através dele podemos construir serviços que podem ser consumidos pela própria empresa ou por parceiros de negócios, para que seja possível criar aplicações inteligentes e conectadas. A finalidade desta palestra é mostrar um overview sobre o WCF, abordando superficialmente as funcionalidades incluídas na versão 4.0, com exemplos práticos de sua utilização.

Community Launch em Piracicaba

No próximo dia 17 de abril acontecerá um evento chamado de Community Launch. Esse evento será espalhado por todo o Brasil, onde cada região criará o evento e abordará os principais produtos da Microsoft que estarão sendo lançados neste ano de 2010, a saber: Visual Studio 2010, Windows Server 2008 R2 e SQL Server 2008 R2.

Para quem é de Piracicaba e região, este evento acontecerá na Faculdade Salesiana Dom Bosco, à partir das 08:30 da manhã. Para maiores detalhes, consulte o site do evento. Entre as várias palestras, eu sou o responsável por falar sobre o WCF – Windows Communication Foundation. É importante dizer que a palestra será de nível 100, abordando superficialmente algumas das principais funcionalidades e mudanças que aconteceram nesta nova versão da tecnologia. Abaixo temos a descrição da palestra:

Título: Overview do WCF
Palestrante: Israel Aece
Descritivo: O WCF é o pilar de comunicação da plataforma .NET, e que está presente desde a versão 3.0. Através dele podemos construir serviços que podem ser consumidos pela própria empresa ou por parceiros de negócios, para que seja possível criar aplicações inteligentes e conectadas. A finalidade desta palestra é mostrar um overview sobre o WCF, abordando superficialmente as funcionalidades incluídas na versão 4.0, com exemplos práticos de sua utilização.

IMPORTANTE: Apesar do evento ser gratuito, para poder participar é necessário efetuar o cadastro aqui.