Expondo Tipos POCO através do WCF

Ao construir serviços WCF, podemos expor tipos que vão além dos tipos tradicionais (tais como strings, inteiros, etc.), ou seja, podemos recorrer a construção de tipos customizados, onde construimos classes com suas propriedades que determinam os dados que serão carregados entre o cliente e o serviço.

Algumas vezes essas classes são construídas com o intuito de atender a requisição e/ou resposta das operações de um determinado serviço, mas que internamente, são consultas que fazemos no banco de dados e estamos retornando ao cliente, ou ainda, são comandos que devemos executar, também no banco de dados, para persitir alguma informação.

Se optarmos pelo uso do Entity Framework, podemos utilizar o modelo de geração POCO, onde as classes geradas são consideradas “puras”, ou seja, não dependem de nenhuma classe do framework de persistência. Isso tornam as classes simples, apenas com as propriedades que são, em princípio, mapeadas para colunas da base de dados. Sendo assim, muitos podem optar pela exposição direta destas classes no contrato de um serviço WCF, evitando assim a criação de outras classes (DTOs) para efetuar o transporte das informações.

Mas expor diretamente essas classes podem acarretar alguns problemas. A questão é que entidades que foram geradas utilizando o modelo POCO, possuem um comportamento durante a execução diferente das entidades que são geradas pelo modelo padrão do Entity Framework. Quando utilizamos o modelo padrão, as entidades herdam diretamente da classe EntityObject, que fornece toda a infraestrutura necessária para efetuar o rastreamento das mudanças e dá também o suporte ao lazy-loading. Quando utilizamos classes POCO, esses recursos continuam sendo oferecidos, mas são implementados de forma diferente.

Neste caso, o Entity Framework gera proxies dinâmicos para interceptar os acessos às propriedades das entidades que estão sendo manipuladas, e com isso, todos os recursos acima, continuam ainda sendo suportados. Abaixo temos o objeto Type da classe que foi gerada dinamicamente.

{System.Data.Entity.DynamicProxies.Cliente_B38C1C71074F1A0CDCF11548021F55AF4BAC2116057847A45ACD8E600D02BB90}

Só que ao expor esse tipo de objeto diretamente através do WCF, vamos nos deparar com uma exceção durante a execução. Isso se deve ao fato de que o WCF não é capaz serializar/deseralizar tipos que não são conhecidos pelo mesmo. Ao construir o contrato para um serviço WCF, você pode mencionar os tipos das classes geradas efetivamente pelo EDMX, mas durante a execução, o tipo acima será criado e, consequentemente, será entregue para a infraestrutura do WCF, ele irá se certificar de que o tipo é conhecido no contrato, e como não é, a exceção será disparada.

Há algumas alternativas para evitar esse problema. A primeira delas é desabilitar a criação do proxy dinâmico através da propriedade boleana ProxyCreationEnabled, que está acessível através do contexto do Entity Framework, assim como é exibido no código abaixo. O problema é que ao fazer isso, entidades criadas no padrão POCO não serão capazes de fornecer as funcionalidades de rastreamento de mudanças e lazy-loading.

public class Servico : IContrato
{
    public Cliente Recuperar(int id)
    {
        using (DBTestesEntities1 ctx = new DBTestesEntities1())
        {
            ctx.ContextOptions.ProxyCreationEnabled = false;

            return (from c in ctx.Cliente where c.ClienteId == id select c).Single();
        }
    }
}

A outra opção é a criação de um behavior que pode ser aplicado em nível de operação, alterando o serializador padrão do WCF, que é o DataContractSerializer, para o serializador ProxyDataContractResolver. Este serializador, que está debaixo do namespace System.Data.Objects, ajuda na resolução dos tipos que são criados dinamicamente pelo Entity Framework em “tipos concretos”, recorrendo ao método estático GetObjectType, exposto através da classe ObjectContext, que dado o Type do proxy dinâmico, ele retorna o tipo correspondente POCO, informando ao WCF que Type correto para que ele possa ser capaz de serializá-lo. Abaixo temos um exemplo da implementação e aplicação deste behavior:

public class ProxyDataResolverAttribute : Attribute, IOperationBehavior
{
    public void ApplyDispatchBehavior(OperationDescription opDescription, DispatchOperation dop)
    {
        opDescription
            .Behaviors
            .Find<DataContractSerializerOperationBehavior>()
            .DataContractResolver = new ProxyDataContractResolver();
    }

    //outros métodos
}

[ServiceContract]
public interface IContrato
{
    [OperationContract]
    [ProxyDataResolver]
    Cliente Recuperar(int id);
}

E, finalmente, uma terceira opção, seria a utilização de DTOs (Data Transfer Objects), onde você pode definir os objetos que quer trafegar entre as partes, sem a necessidade de se preocupar com detalhes de uma tecnologia específica que esteja utilizando nos bastidores e, principalmente, de ter a possibilidade de desacoplar complementamente o que representa os seus dados/domínio daquilo que quer expor para os clientes/parceiros.

Autorização Simplista no ASP.NET

O Forms Authentication é o mecanismo que temos desde a primeira versão do ASP.NET, e que hoje faz parte do seu core, e é responsável pelo gerenciamento do processo de autenticação de um usuário, utilizando cookies. É importante dizer que este recurso apenas se encarrega de gerenciar o cookie que é criado, se certificando de que ele existe, é válido e não está expirado, atuando como um “guarda” logo nos primeiros estágios da requisição.

Só que a verificação quanto a existência daquele usuário é importante, e temos algumas opções para isso. Uma delas é recorrer à um banco de dados customizado, um arquivo Xml, ou ainda, utilizar toda a infraestrutura que o ASP.NET fornece a partir da versão 2.0, conhecida como Membership. Além dessas alternativas, para alguns cenários extremamente simplistas, podemos utilizar o próprio arquivo Web.config para armazenar os usuários. Para isso, utilizamos o sub-elemento credentials do elemento forms, que é utilizado para configurar o Forms Authentication. Abaixo temos este exemplo:

<?xml version=”1.0″?>
<configuration>
  <system.web>
    <authentication mode=”Forms”>
      <forms loginUrl=”~/PaginaDeLogin.aspx”>
        <credentials passwordFormat=”Clear”>
          <user name=”Israel” password=”123″/>
          <user name=”Claudia” password=”456″/>
        </credentials>
      </forms>
    </authentication>
  </system.web>
</configuration>

Com os usuários ali catalogados, para que seja possível verificar a existência do mesmo, recorremos ao método estático Authenticate da classe FormsAuthentication. Este método receberá duas strings, que correspondem ao login e senha, retornando um valor boleano indicando se o usuário existe ou não dentro do arquivo de configuração. Isso é o suficiente para manter os usuários da aplicação, sem necessitar de algum recurso extra para armazenar os usuários. Abaixo o código que faz essa checagem:

if (FormsAuthentication.Authenticate(this.Login.Text, this.Senha.Text))
    FormsAuthentication.RedirectFromLoginPage(this.Login.Text, false);

Apesar da Microsoft suportar um modelo de gerenciamento de usuários de forma simples, ela não disponibiliza um recurso nesta mesma linha para armazenar os papéis do usuário. Talvez isso se deva ao fato de isso já deve ser encarado como sendo algo mais rebuscado, ou seja, devendo recorrer à algo mais elegante para o gerenciamento de usuários e seus respectivos papéis. Mas para aqueles que ainda desejam manter a simplicidade, você pode ter isso com um pouco de trabalho. O primeiro passo consiste na criação de um arquivo para armazenar os papéis, e para isso vamos utilizar o formato Xml, relacionando os papéis através do nome do usuário. Abaixo temos o conteúdo do arquivo que chamei de userRoles.config, mas que não possui nenhuma relação com o arquivo de configuração da aplicação, o Web.config.

<?xml version=”1.0″?>
<userRoles>
  <user name=”Israel”>
    <roles>
      <role name=”Admin” />
      <role name=”TI” />
    </roles>
  </user>
  <user name=”Claudia”>
    <roles>
      <role name=”Gerencia” />
    </roles>
  </user>
</userRoles>

Com todos papéis ali definidos, precisamos criar uma classe que será responsável pela busca e extração dos papéis de um determinado usuário. Essa classe estática, chamada de ConfigurationRoles, é extremamente simples, que expõe um método chamado GetRolesByUser, e que recebe o nome do usuário, e efetua a busca no arquivo userRoles.config utilizando LINQ To Xml, e caso encontre-o, retornará um array de strings, onde cada elemento corresponde à um papel em que o usuário está contido. Abaixo temos a classe que acabou de ser descrita:

internal static class ConfigurationRoles
{
    private static readonly string RolesFilePath;

    static ConfigurationRoles()
    {
        RolesFilePath = HttpContext.Current.Server.MapPath(“~/userRoles.config”);
    }

    internal static string[] GetRolesByUser(string username)
    {
        XDocument doc = XDocument.Load(RolesFilePath);

        return
            (
                from u in doc.Descendants(“user”)
                where u.Attribute(“name”).Value == username
                from r in u.Descendants(“role”)
                select r.Attribute(“name”).Value
            ).ToArray();
    }
}

Só que ainda nos resta utilizar isso na aplicação. Para interceptar o processo de autenticação, podemos utilizar o evento Authenticate da classe FormsAuthenticationModule, que é o responsável por gerenciar o processo da autenticação através do Forms Authentication. Esse evento nos permitirá a customização do objeto que representa o usuário (IIdentity) e seus papéis (IPrincipal), que é exatamente o que precisamos fazer. Para tratarmos o evento, criamos no arquivo Global.asax um método nomeado como FormsAuthentication_OnAuthenticate, que automaticamente o ASP.NET o invocará quando o evento Authenticate acontecer. Abaixo temos a o código referente a este processo:

public class Global : HttpApplication
{
    public void FormsAuthentication_OnAuthenticate(object sender, FormsAuthenticationEventArgs e)
    {
        if (FormsAuthentication.CookiesSupported)
        {
            if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
            {
                FormsAuthenticationTicket ticket =
                    FormsAuthentication.Decrypt(
                        Request.Cookies[FormsAuthentication.FormsCookieName].Value);

                string username = ticket.Name;

                e.User =
                    new GenericPrincipal(
                        new GenericIdentity(username),
                        ConfigurationRoles.GetRolesByUser(username));
            }
        }
        else
        {
            throw new HttpException(“Modelo de autenticação não suportado.”);
        }
    }
}

Note que se houver um cookie de autenticação criado, decriptamos o mesmo extraindo o nome do usuário. Em seguida, construímos uma nova identidade a partir daquele nome de usuário, e recorremos a classe que criamos acima, extraindo todos os papéis daquele usuário, envolvendo tudo isso em um objeto chamado GenericPrincipal. Note que a instância é atribuída à propriedade User do parâmetro FormsAuthenticationEventArgs que é passado ao método, e que a partir de agora, será utilizado por toda aplicação.

Apesar de tudo isso funcionar, ele deve ser utilizado em casos realmente simples, onde a demanda por gerenciar usuários e papéis em tempo de execução não seja necessária. Do contrário, o melhor é recorrer à alguns recursos que já temos à disposição tanto para o gerenciamento de usuários como o de papéis.

WCF Web API – API Key Verification

Quando criamos algum tipo de serviço, em princípio nos concentramos nas funcionalidades e informações que ele irá expor aos consumidores. Depois disso, nos preocuparemos em analisar o contexto de segurança, verificando o tipo de autenticação e nível de autorização que são necessários para o serviço funcionar de forma segura.

O detalhe é que muitas vezes não queremos envolver qualquer mecanismo de autenticação e autorização no serviço, já que ele poderá ser acessado de forma pública, sem qualquer necessidade do consumidor efetivamente se cadastrar, gerar um login e senha e, finalmente, acessar o respectivo serviço, apresentando à ele essas informações. Mas apesar do cliente não se identificar com um login e senha, não quer dizer que nosso serviço não precise ser “protegido” de alguma outra forma.

A questão é que permitindo o acesso irrestrito total, permite com que bons usuários o acessem da forma legal, e também permite com que outros usuários, estes mal intencionados, disparem uma infinidade de requisições contra o serviço, e se este, por sua vez, pode estar consumindo recursos caros, com por exemplo, acessando uma base de dados, em pouco tempo nosso servidor estará esgotado, não conseguindo atender nem mesmo aqueles que usam o serviço da forma correta.

Uma técnica chamada API Key Verification foi criada com o intuito de evitar esse tipo de problema. Com uma implementação simples, criamos e mantemos uma lista de chaves (podendo ser strings, inteiros, Guids, etc.) que estão habilitadas à acessarem o serviço. Os consumidores podem receber esta chave de alguma forma (out-of-band ou não), como por exemplo, fazendo um cadastro no site da empresa demonstrando o interesse; mais tarde, ele receberá um e-mail contendo a chave que foi criada exclusivamente para o mesmo, e que deverá ser utilizada quando efetuar uma requisição para o serviço, embutindo-a na coleção de headers ou querystrings, de acordo com o que você determinar. Ao chegar a requisição no serviço, você detecta a presença desta informação, e se a chave não fizer parte da requisição ou for uma chave inválida, deveremos rejeitar a mesma.

A ideia deste artigo é mostrar como podemos implementar esta validação utilizando a nova API do WCF, chamada WCF Web API. Para isso, vamos recorrer à um recurso exposto por ela, chamado de Message Handlers. Esses handlers são acoplados ao runtime, e são executados durante os primeiros estágios da requisição, antes mesmo do serviço ser efetivamente executado. Para maiores detalhes sobre os Message Handlers, consulte este artigo. Abaixo temos a implementação deste handler que validará a chave que o consumidor está nos encaminhando:

public class ApiKeyVerificationMessageHandler : DelegatingChannel
{
    private readonly IRepositorioDeChaves repositorioDeChaves;
    private const string API_KEY = “apiKey”;

    public ApiKeyVerificationMessageHandler(HttpMessageChannel inner, IRepositorioDeChaves repositorio)
        : base(inner)
    {
        this.repositorioDeChaves = repositorio;
    }

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellation)
    {
        var queryStrings = HttpUtility.ParseQueryString(request.RequestUri.Query);
        var chave = Guid.Empty;

        if (Guid.TryParse(queryStrings[API_KEY], out chave) && repositorioDeChaves.VerificarSeExiste(chave))
            return base.SendAsync(request, cancellation);

        return Task.Factory.StartNew(() => new HttpResponseMessage(HttpStatusCode.Unauthorized, “A chave fornecida é inválida.”));
    }
}

Analisando a classe acima, podemos perceber que no construtor recebemos a instância de alguma classe que implemente a interface IRepositorioDeChaves. Utilizamos a interface aqui, justamente para tornar o nosso handler independente do local onde desejamos armazenar as chaves. Para efeito de testes, optei por criar uma implementação em memória e que ocultarei aqui por questões de espaço, mas você poderá recorrer a qualquer outro meio, como XML, SQL, etc. Em seguida, sobrescrevemos o método SendAsync (exposto pela classe DelegatingChannel), onde detectamos se existe ou não uma query string chamada apiKey, e se houver, fazemos o parser da mesma através do Guid, que é o tipo de dado que estamos utilizando para determinar o tipo das chaves que dão acesso ao serviço. Não existindo a chave na query string ou ela sendo inválida, retornamos uma mensagem informando o status como 401, que indica que a requisição não foi autorizada à acessar o serviço.

Depois disso, precisamos acoplar esse handler à execução, e para isso, utilizamos o evento ApplicationStart do arquivo Global.asax, onde vamos criar a factory responsável pela criação do handler. Essa factory será responsável por instanciar a classe ApiKeyVerificationMessageHandler que criamos acima, passando o repositório de chaves em memória que também criamos e configuramos dentro deste evento. Note que estou utilizando uma sobrecarga do método SetMessageHandlerFactory, que me permite passar um delegate contendo o código de construção do objeto, mas se quiser algo mais rebuscado, poderia construir uma factory herdando da classe HttpMessageHandlerFactory.

protected void Application_Start(object sender, EventArgs e)
{
    RepositorioDeGuidsEmMemoria repositorio = new RepositorioDeGuidsEmMemoria();
    repositorio.Adicionar(new Guid(“d4907f3c-52c7-457e-9c18-e5abf9be77fe”));
    repositorio.Adicionar(new Guid(“adc5c096-fdc3-4c57-a887-ba4a368f299f”));

    var config =
        HttpHostConfiguration
            .Create()
            .SetMessageHandlerFactory(inner => new ApiKeyVerificationMessageHandler(inner, repositorio));

    RouteTable.Routes.MapServiceRoute<ServicoDeTeste>(“teste”, config);
}

Depois dessas customizações, podemos utilizar o Fiddler para efetuar e capturar as requisições para o serviço. Para exemplificar, a primeira requisição informa um elemento chamado apiKey na coleção de query strings. Isso fará com que o serviço entregue a resposta da forma correta. Já na segunda requisição, omitimos a chave, fazendo com que o a resposta seja definida como 401, como também podemos perceber abaixo:

— Primeira Requisição
GET http://localhost:1830/teste/ping?apiKey=d4907f3c-52c7-457e-9c18-e5abf9be77fe&value=sss HTTP/1.1
User-Agent: Fiddler
Host: localhost:1830

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

<?xml version=”1.0″ encoding=”utf-8″?><string>sss ping</string>

— Segunda Requisição
GET http://localhost:1830/teste/ping?value=sss HTTP/1.1
User-Agent: Fiddler
Host: localhost:1830

— Resposta
HTTP/1.1 401 Unauthorized
Content-Length: 0
Connection: Close

Além do que foi apresentado aqui, você ainda poderia criar políticas para renovação e revogação de chaves, e além disso, permitir com que o consumidor mande a chave na coleção de query strings ou de headers, podendo o handler ser inteligente o bastante para ser capaz de detectar em ambos os locais, e caso não encontrado, rejeitaria do mesmo jeito.

WCF Web API – Formulários

Sabemos que temos vários métodos suportados pelo protocolo HTTP, e entre eles, os mais comuns que vemos e utilizamos é o GET e o POST. Na primeira opção, o que enviamos ao servidor durante a requisição é o cabeçalho contendo tudo o que é necessário para efetuá-la, sem qualquer informação extra no corpo da mensagem. Ao contrário do que ocorre com o verbo POST, que além das informações que vão no cabeçalho, podemos também enviar qualquer conteúdo no corpo da mensagem.

Obviamente que o entendimento deste conteúdo por parte do serviço está condicionado ao header chamado Content-Type. Entre os vários tipos de conteúdo, temos os formatos Xml e Json. Mas ainda existe um outro formato, que também é muito comum em aplicações Web, que é conhecido como application/x-www-form-urlencoded. Este é o formato padrão que é utilizado pelo navegador, quando ele efetua um POST de um formulário HTML, codificando os campos existentes no mesmo, em uma coleção de pares de chave e valor.

Abaixo temos uma página HTML de exemplo, que contém um formulário simples, com dois campos do tipo Text e um botão que submete o formulário para o serviço que vamos criar mais tarde. Note que os controles estão envolvidos por um elemento chamado form, que contém o endereço (action) para onde o formulário será postado.

<form action=”http://localhost:1989/paginas/Enviar&#8221; method=”post”>
  <input type=”text=” id=”Nome” name=”Nome” />
  <input type=”text=” id=”Cpf” name=”Cpf” />
  <input type=”submit” name=”Enviar” value=”Enviar” />
</form>

Ao preencher os campos e postar o formulário, podemos capturar a requisição e analisar o que está sendo enviado ao serviço mencionado. Podemos notar a estrutura da requisição abaixo, e que alguns headers menos relevantes para a situação, foram omitidos por questões de espaço. A nossa análise começa pelo header, onde temos o Content-Type definido como application/x-www-form-urlencoded, que como falamos acima, corresponde ao valor padrão para formulários HTML. No corpo da mensagem temos os campos do formulário separados pelo caracter &. Já os espaços são substituídos pelo caracter +. E, para finalizar, o nome do controle é definido como chave, enquanto o conteúdo do controle é definido como valor na coleção.

POST http://localhost:1989/paginas/Enviar HTTP/1.1
Accept-Language: en-US,pt-BR;q=0.5
Content-Type: application/x-www-form-urlencoded
Connection: Keep-Alive
Content-Length: 50
Host: localhost:1989

Nome=Israel+Aece&Cpf=111.222.333-44&Enviar=Enviar

O WCF Web API possibilita a leitura deste tipo de requisição, e para isso, temos um media type específico, chamado de FormUrlEncodedMediaTypeFormatter. Em um artigo anterior eu comentei sobre os media types, mais deixei este media type de fora justamente para abordá-lo aqui. Assim como os media types Xml e Json, este também é adicionado por padrão à execução, mapeando o tipo application/x-www-form-urlencoded como sendo o formato que ele interpreta.

Quando você requisita alguma informação para um serviço construído sobre essa nova API, a escolha do media type é realizada no interior da classe ObjectContent, através de um método protegido chamado SelectReadFormatter. Esse método percorre os formatadores que temos adicionados, verificando se o tipo de conteúdo da requisição é suportado por ele, e sendo, ele é imediatamente retornado para que o próprio ObjectContent possa ler o conteúdo utilizando-o. Com o formatador em mãos, a classe ObjectContent invoca o método ReadFromStream, exposto pela classe MediaTypeFormatter, repassando a ele o stream contendo o corpo da requisição, que fará o parser da mesma, e devolvendo para o serviço o objeto já deserializado. Abaixo temos um método simples, chamado Enviar, que recebe a requisição do formulário HTML que fizemos acima:

[WebInvoke]
public HttpResponseMessage Enviar(HttpRequestMessage request)
{
    var conteudo = request.Content.ReadAsString();

    return new HttpResponseMessage() { Content = new StringContent(conteudo) };
}

O grande problema do código acima, é que estamos lendo o corpo da mensagem como uma string, ficando difícil manipular e extrair informações do conteúdo enviado pelo cliente. Há algumas alternativas para conseguirmos extrair informações de uma forma mais amigável. A primeira delas é utilizando o método estático chamado ParseQueryString, da classe HttpUtility. Esse método recebe uma string e faz o parser dela, retornando o resultado (chaves e valores), em uma coleção especializada do tipo NameValueCollection. É importante lembrar que esta coleção é uma espécie de dicionário, suportando apenas strings como chave e como valor, e sua principal característica é não permitir chaves duplicadas, assim como qualquer dicionário, mas ela consegue agrupar valores que tenham a mesma chave, dentro de em um mesmo item. O código abaixo ilustra essa nova versão:

[WebInvoke]
public HttpResponseMessage Enviar(HttpRequestMessage request)
{
    var conteudo = HttpUtility.ParseQueryString(request.Content.ReadAsString());
    var resultado = new StringBuilder();

    foreach (var item in conteudo.AllKeys)
        resultado.AppendLine(string.Format(“{0}: {1}”, item, conteudo[item]));

    return new HttpResponseMessage()
    {
        Content = new StringContent(resultado.ToString())
    };
}

A outra opção que temos, é utilizando classes que correspondem ao formato Json. Há um método estático chamado ParseFormUrlEncoded, fornecido pela classe FormUrlEncodedExtensions, que dado uma string representando o corpo codificado no formato que estamos vendo neste artigo, ele retorna um objeto do tipo JsonObject, que nada mais é do que uma espécie de dicionário, onde a chave é do tipo string e o valor do tipo JsonValue. Estes objetos também fazem parte desta nova API, quais já discuti neste outro artigo com maiores detalhes.

[WebInvoke]
public HttpResponseMessage Enviar(HttpRequestMessage request)
{
    var conteudoCodificado = request.Content.ReadAsString();
    var conteudo = FormUrlEncodedExtensions.ParseFormUrlEncoded(conteudoCodificado);

    HttpResponseMessage response = new HttpResponseMessage();
    response.Content = new ObjectContent<JsonValue>(conteudo);
    response.Content.Headers.ContentType = new MediaTypeHeaderValue(“application/json”);

    return response;
}

Depois de extrair a string contendo o corpo da requisição, submetemos a mesma para o método ParseFormUrlEncoded, que retornará o objeto JsonObject com todo o conteúdo já no formato Json. Depois disso, definimos o objeto construído como corpo da mensagem de resposta e, finalmente, definimos o tipo da resposta como sendo do tipo application/json. Abaixo temos a resposta sendo devolvida para o cliente, retornando conforme o esperado:

HTTP/1.1 200 OK
Content-Length: 63
Content-Type: application/json

{“Nome”:”Israel Aece”,”Cpf”:”111.222.333-44″,”Enviar”:”Enviar”}

Como vimos acima, o formato em que o formulário é encaminhado para o serviço, pode ser convertido implicitamente para Json, dando assim, um maior poder na manipulação da requisição e na geração dos resultados. Isso quer dizer que podemos também receber um conteúdo em formato application/x-www-form-urlencoded defindo no parâmetro do método, o tipo JsonObject ou invés de lidar diretamente com a classe HttpRequestMessage. Abaixo temos o método Enviar refletindo essa alteração:

[WebInvoke]
public HttpResponseMessage Enviar(JsonValue conteudo)
{
    HttpResponseMessage response = new HttpResponseMessage();
    response.Content = new ObjectContent<JsonValue>(conteudo);
    response.Content.Headers.ContentType = new MediaTypeHeaderValue(“application/json”);

    return response;
}

Finalmente, podemos utilizar o método AsDinamyc da classe JsonValue, que converte o nosso objeto em um tipo dinâmico, que permite burlar a verificação estática dos membros, fazendo isso somente em tempo de execução. Abaixo temos esse exemplo, e logo na sequência, o resultado gerado por este método e que foi capturado. Note que o código fica muito mais simples e expressivo.

[WebInvoke]
public HttpResponseMessage Enviar(JsonValue conteudo)
{
    dynamic valores = conteudo.AsDynamic();

    return new HttpResponseMessage()
    {
        Content = 
            new StringContent(string.Format(“Nome: {0} – C.P.F.: {1}”, valores.Nome, valores.Cpf))
    };
}

HTTP/1.1 200 OK
Content-Length: 46
Content-Type: text/plain; charset=iso-8859-1

Nome: “Israel Aece” – C.P.F.: “111.222.333-44”

WCF Web API – Testes

Há alguns dias eu mostrei aqui, que o WCF Web API possibilita a construção de serviços de modelo tradicional WCF, ou seja, definir tipos que refletem o nosso negócio (Cliente, Produto, Pedido, etc.), bem como tipos mais simples (inteiro, string, boleano, etc.). Como sabemos, a finalidade é conseguir desenhar um serviço que nada saiba sobre a infraestrutura, como ele é exposto, características, etc.

Naquela mesma oportunidade, eu comentei sobre a possibilidade que temos de receber e/ou retonar objetos que refletem e fazem uso da estrutura do protocolo HTTP, que é um detalhe muito importante na estrutura REST. Ao utilizar as classes que descrevem a requisição (HttpRequestMessage) e a resposta (HttpResponseMessage), podemos interagir com detalhes do protocolo, que antes exigia-se um conhecimento de baixo nível do WCF.

Como sabemos, assim como já acontece com os serviços tradicionais construídos em WCF, podemos aplicar testes em cima da classe que representa o serviço sem maiores problemas. Isso se deve ao fato de que em ambos os modelos que temos agora, como eles são simples classes, com métodos que executam tarefas e, eventualmente, retornam algum resultado.

Mas e quando queremos receber e/ou enviar dados para este serviço, utilizando instâncias das classes HttpRequestMessage e HttpResponseMessage? Felizmente, assim como no ASP.NET MVC, a Microsoft está desenhando o WCF Web API com a possibilidade de testá-lo sem estar acoplado à infraestrutura do WCF, o que permite testar a classe do serviço, mesmo que ela receba ou devolva objetos característicos do protocolo HTTP.

Se repararmos no artigo anterior, onde eu mostro um serviço que possui dois métodos (Ping e PingTipado), podemos escrever testes e, consequentemente, utilizar a IDE do Visual Studio para executá-los, e como isso, nos antecipamos à eventuais problemas que possam acontecer, pois talvez seja possível capturar alguns desses problemas antes mesmo de levar o mesmo ao ambiente de produção.

No primeiro exemplo, estamos testando o método Ping, instanciando a classe que representa o serviço, e passando ao método Ping a instância da classe HttpRequestMessage. Neste momento, poderíamos abastecer informações na coleção de headers da requisição, com o intuito de fornecer tudo o que é necessário para o que o método/teste possa executar com sucesso. Depois da requisição realizada, verificamos se o status da resposta corresponde ao status OK.

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

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

O próximo passo é construir um teste para o método PingTipado. Esse método recebe como parâmetro a instância da classe HttpRequestMessage<T>, definindo o parâmetro genérico T como sendo do tipo Informacao. A finalidade do teste é assegurar que, se passarmos uma instância nula da classe Informacao, uma exceção do tipo HttpResponseException deverá ser lançada. O código abaixo ilulstra este teste:

[TestMethod]
[ExpectedException(typeof(HttpResponseException))]
public void DadoUmObjetoInfoNuloDeveDispararUmErro()
{
    var response =
        new ServicoDeExemplo()
            .PingTipado(new HttpRequestMessage<Informacao>(null));
}

Finalmente, o próximo passo consiste em criar um teste, também para o método PingTipado, mas agora fornecendo a instância do objeto Informacao em um estado válido, para que o teste possa suceder se o serviço retornar a mesma instância da classe Informacao, onde os membros da requisição reflitam o que está sendo retornado como reposta. Abaixo o código que efetua o tal teste:

[TestMethod]
public void DadoUmObjetoInfoDeveRetornarEleComInformacoesExtra()
{
    var request = new Informacao() { Codigo = “123”, Dado = “Alguma Info” };
    var response =
        new ServicoDeExemplo()
            .PingTipado(new HttpRequestMessage<Informacao>(request))
            .Content
            .ReadAs();

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

WCF Web API – Media Types

Ao efetuar uma requisição para algum recurso sobre o protocolo HTTP, o servidor identifica o mesmo, faz o processamento, gera o resultado e, finalmente, devolve o resultado para o cliente que fez a solicitação. Por mais que isso não fica explícito, o conteúdo que trafega do cliente para o servidor (requisição) e do servidor para o cliente (resposta), sempre possui um formato específico.

Em grande parte de todos os recursos fornecidos através do protocolo HTTP, uma das necessidades é justamente definir o formato deste conteúdo, que por sua vez, direciona a interpretação pelo navegador, por uma outra aplicação ou até mesmo de uma biblioteca, permitindo efetuar o parser do resultado e, consequentemente, materializar o mesmo em algo “palpável”/visível.

Os formatos são representados por uma simples string, onde você tem uma primeira parte para descrever qual o tipo de conteúdo, e depois o seu formato. Por exemplo, ao invocar uma página onde o retorno é um conteúdo HTML, o formato será definido como text/html; ao solicitar uma imagem, o seu formato será definido como image/jpeg. Uma lista contendo todos os formatos de conteúdos disponíveis na internet, é gerenciada e mantida por entidade chamada IANA, e pode ser acessada aqui.

Como o WCF Web API tem uma forte afinidade com as características do HTTP, ele permite receber ou gerar conteúdos em formatos popularmente conhecidos pelo mercado. A finalidade deste artigo é mostrar como podemos proceder para configurar, utilizar e customizar os media types para os serviços. Em primeiro lugar, precisamos analisar a estrutura da classe que representa um media type. Para isso, a Microsoft criou uma classe abstrata chamada de MediaTypeFormatter, e já existem algumas implementações definidas dentro da API, como por exemplo, as classes XmlMediaTypeFormatter e JsonMediaTypeFormatter. A imagem abaixo mostra essa herança:

Como podemos perceber, os serviços que criamos utilizando essa nova API nada sabem sobre o formato em que ele chegou ou o formato em que ele será devolvido para o cliente. Na verdade o que ocorre é que os media types já são acoplados à execução, e para isso, a Microsoft utilizou um recurso de estensibilidade desta API, que são os operation handlers. Existem duas classes públicas chamadas RequestContentHandler e ResponseContentHandler, e como os próprios nomes dizem, fazem parte da requisição e da resposta, respectivamente.

Essas duas classes possuem uma propriedade chamada Formatters, que é uma coleção do tipo MediaTypeFormatterCollection. Ambos handlers já possuem as classes XmlMediaTypeFormatter (application/xml) e JsonMediaTypeFormatter (application/json) adicionadas por padrão. Através da imagem abaixo podemos visualizar onde se encontram cada um destes objetos que vimos acima:

Olhando para a imagem acima, uma pergunta que aparece é como o WCF escolhe qual dos formatadores utilizar. A escolha se baseia no formato solicitado pelo cliente. O formato pode ser incluído como um item na requisição, através do header Accept ou do Content-Type. O WCF escolhe o formatador de acordo com o valor que ele encontra em um desses headers, e caso o formato definido não for encontrado, o padrão é sempre devolver o conteúdo em formato Xml.

Customização

Apesar do Xml e Json serem os principais formatos que temos atualmente, pode haver situações onde desejamos criar um formato próprio, para que esse possa gerar e/ou receber o conteúdo em um formato específico. Como já percebemos acima, se desejarmos fazer isso, temos que recorrer à implementação da classe abstrata MediaTypeFormatter, customizando basicamente dois métodos principais OnReadFromStream e OnWriteToStream. Vamos analisar cada um desses métodos abaixo:

  • OnCanReadType: Dado um objeto do tipo Type, este método retorna um valor boleano (onde o padrão é True), indicando se aquele tipo é ou não entendido por aquele formatador. O tipo identifica os eventuais parâmetros que existem no método do serviço. Aqui podemos fazer validações, como por exemplo, identificar se o tipo é ou não serializável, se possui um determinado atributo, etc.
  • OnReadFromStream: Se o método acima retornar True, então este método é executado. Como parâmetro ele recebe o tipo do objeto (o mesmo que foi passado para o método acima), e um objeto do tipo Stream, que é fonte das informações (estado) do objeto a ser criado. Este método retorna um object, que corresponde à um objeto criado dinamicamente e configurado com os valores provenientes do Stream.
  • OnCanWriteType: Dado um objeto do tipo Type, este método retorna um valor boleano (padrão é True), indicando se aquele tipo é ou não entendido pelo formatador. O tipo identifica o retorno do método do serviço. Aqui podemos fazer validações, como por exemplo, identificar se o tipo é ou não serializável, se possui um determinado atributo, etc.
  • OnWriteToStream: Se o método acima retornar True, então este método é executado. Como parâmetro, ele recebe o tipo do objeto a ser serializado e um object que corresponde a instância do objeto a ser gravado. Ainda recebemos um Stream, que é o destino do objeto serializado.

Para podemos exemplificar, vamos criar um formatador específico para o formato CSV, que é um padrão bem tradicional, onde cada valor é separado pelo caracter “;”. Abaixo temos a classe CsvMediaTypeFormatter, que herda de MediaTypeFormatter. O que vemos de interessante no trecho de código abaixo, é a definição do formato application/csv sendo adicionado à coleção de media types suportados por este formatador customizado, que está acessível através da propriedade SupportedMediaTypes.

public class CsvMediaTypeFormatter : MediaTypeFormatter
{
    private const char SEPARATOR = ‘;’;

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

    public override object OnReadFromStream(Type type, Stream stream, HttpContentHeaders contentHeaders)
    {
        //implementação
    }

    public override void OnWriteToStream(Type type, object value, Stream stream, HttpContentHeaders contentHeaders, TransportContext context)
    {
        //implementação
    }
}

A implementação é bastante trivial, e optei por não colocar toda ela aqui por questões de espaço. A implementação na íntegra está no arquivo que está vinculado à este artigo. De qualquer forma, ao gerar um conteúdo, estou analisando se o objeto é ou não uma coleção; se for, fazemos um trabalho diferenciado para capturar o tipo concreto do elemento que temos. Depois de chegar no elemento concreto, percorremos os itens da coleção, extraindo via Reflection, os valores das propriedades de cada item. Caso seja um objeto único, apenas extraímos as suas respectivas propriedades. Para ambos os casos, depois de encontrar o tipo concreto, percorremos as propriedades capturando os respectivos nomes, para que seja possível gerar o header do conteúdo.

Já quando lemos o conteúdo que está chegando ao serviço, extraímos a primeira linha (header do conteúdo) para capturar as propriedades que temos dentro do corpo da mensagem. Em seguida, se for uma coleção, criamos dinamicamente a instância de um objeto que implementa a interface IList, e para cada linha subsequente, criamos a instância do tipo concreto, adicionando na coleção criada no passo anterior. Caso seja um objeto único, tudo o que fazemos é instânciá-lo, configurar as propriedades e retorná-lo ao WCF.

Como já era esperado, o que precisamos fazer a partir de agora é instalá-lo à execução. E para isso, recorremos à classe HttpHostConfiguration, que através do método AddFormatters, podemos incluir classes que herdam de MediaTypeFormatter. O que fazemos aqui é instanciar e adicionar a classe CsvMediaTypeFormatter:

protected void Application_Start(object sender, EventArgs e)
{
    RouteTable.Routes.MapServiceRoute<ServicoDeTeste>(
        “teste”,
        HttpHostConfiguration.Create().AddFormatters(new CsvMediaTypeFormatter()));
}

Para exemplificar, temos alguns métodos definidos no serviço que manda e/ou recebe instância(s) da classe Informacao. Novamente estou omitindo parte da implmentação para poupar espaço. Abaixo temos as assinaturas de cada um desses métodos:

[ServiceContract]
public class ServicoDeTeste
{
    [WebGet]
    public List<Informacao> Exemplo1() { }

    [WebInvoke]
    public List<Informacao> Exemplo2(List<Informacao> info) { }

    [WebGet]
    public Informacao Exemplo3() { }

    [WebInvoke]
    public Informacao Exemplo4(Informacao info) { }

    public class Informacao
    {
        public string Dado { get; set; }
        public string Codigo { get; set; }
    }
}

Finalmente, abaixo temos o log salvo pelo Fiddler das requisições efetuadas para cada um dos métodos de exemplo. Repare que quando enviamos uma requisição via GET, definimos o header Accept como application/csv, para que o WCF utilize o formatador customizado que criamos. Ao enviar uma requisição via POST, também definimos o header Content-Type como application/csv, para indicar ao WCF que o conteúdo está no formato CSV, e deverá utilizar o formatador customizado que entenda este conteúdo. É interessante notar também  que no último log, onde omitimos o header Accept, e o resultado está sendo devolvido em Xml, que conforme foi comentado acima, é o formatador padrão.

Exemplo 1 – Requisição

GET http://localhost:2025/teste/Exemplo1 HTTP/1.1
User-Agent: Fiddler
Host: localhost:2025
Accept: application/csv
Content-Length: 0

Exemplo 1 – Resposta

HTTP/1.1 200 OK
Server: ASP.NET Development Server/10.0.0.0
Date: Wed, 04 May 2011 01:59:48 GMT
X-AspNet-Version: 4.0.30319
Content-Length: 88
Cache-Control: private
Content-Type: application/csv
Connection: Close

Dado;Codigo
Alguma Info;0
Alguma Info;1
Alguma Info;2
Alguma Info;3
Alguma Info;4

————————————————————-

Exemplo 2 – Requisição

POST http://localhost:2025/teste/Exemplo2 HTTP/1.1
User-Agent: Fiddler
Host: localhost:2025
Content-Type: application/csv
Content-Length: 39

Dado;Codigo
Info1;111111
Info2;222222

Exemplo 2 – Resposta

HTTP/1.1 200 OK
Server: ASP.NET Development Server/10.0.0.0
Date: Wed, 04 May 2011 02:04:42 GMT
X-AspNet-Version: 4.0.30319
Content-Length: 41
Cache-Control: private
Content-Type: application/csv
Connection: Close

Dado;Codigo
Info1;111111
Info2;222222

————————————————————-

Exemplo 3 – Requisição

GET http://localhost:2025/teste/Exemplo3 HTTP/1.1
User-Agent: Fiddler
Host: localhost:2025
Accept: application/csv

Exemplo 3 – Resposta

HTTP/1.1 200 OK
Server: ASP.NET Development Server/10.0.0.0
Date: Wed, 04 May 2011 02:06:54 GMT
X-AspNet-Version: 4.0.30319
Content-Length: 30
Cache-Control: private
Content-Type: application/csv
Connection: Close

Dado;Codigo
Alguma Info;334

————————————————————-

Exemplo 4 – Requisição

POST http://localhost:2025/teste/Exemplo4 HTTP/1.1
User-Agent: Fiddler
Host: localhost:2025
Content-Type: application/csv
Content-Length: 29

Dado;Codigo
Algum Teste;1981

Exemplo 4 – Resposta

HTTP/1.1 200 OK
Server: ASP.NET Development Server/10.0.0.0
Date: Wed, 04 May 2011 02:08:32 GMT
X-AspNet-Version: 4.0.30319
Content-Length: 41
Cache-Control: private
Content-Type: application/csv
Connection: Close

Dado;Codigo
Algum Teste ping;1981 ping

————————————————————-

Exemplo 1 (Xml) – Requisição

POST http://localhost:2025/teste/Exemplo4 HTTP/1.1
User-Agent: Fiddler
Host: localhost:2025

Exemplo 1 (Xml) – Resposta

HTTP/1.1 200 OK
Server: ASP.NET Development Server/10.0.0.0
Date: Wed, 04 May 2011 02:13:36 GMT
X-AspNet-Version: 4.0.30319
Content-Length: 412
Cache-Control: private
Content-Type: application/xml; charset=utf-8
Connection: Close

<?xml version=”1.0″ encoding=”utf-8″?>
<ArrayOfInformacao>
  <Informacao>
    <Dado>Alguma Info</Dado>
    <Codigo>0</Codigo>
  </Informacao>
  <Informacao>
    <Dado>Alguma Info</Dado>
    <Codigo>1</Codigo>
  </Informacao>
  <Informacao>
    <Dado>Alguma Info</Dado>
    <Codigo>2</Codigo>
  </Informacao>
  <Informacao>
    <Dado>Alguma Info</Dado>
    <Codigo>3</Codigo>
  </Informacao>
  <Informacao>
    <Dado>Alguma Info</Dado>
    <Codigo>4</Codigo>
  </Informacao>
</ArrayOfInformacao>

TesteComWCFMediaTypes.zip (12.86 kb)

WCF Web API – Operation Handlers

No artigo anterior eu falei sobre os message handlers, que afetam todas as mensagens que chegam à um determinado serviço, e que podemos utilizá-los para implementar alguns recursos como autenticação, autorização, etc. Só que também temos cenários onde queremos afetar apenas uma determinada operação, fornecendo informações que talvez tenham sido omitidas na requisição, eventuais validações, etc.

Com isso, temos mais um ponto de estensibilidade no WCF Web API chamado de Operation Handlers. Depois da requisição passar pelos eventuais Message Handlers e da criação da classe que representa o serviço, momentos antes de executar a requisição solicitada, entram em cena os Request Operation Handlers. Na sequência, executa a requisição solicitada, e antes de devolver para o cliente, executa também os Response Operation Handlers, caso eles existam. Como podemos perceber, os Operation Handlers estão divididos em duas partes, onde temos aqueles que são executados antes da requisição ser executada, e aqueles que são executados depois que a requisição foi atendida. A imagem abaixo ilustra esse fluxo:

A implementação deste handler consiste em criar uma classe que herda da classe abstrata HttpOperationHandler. Essa classe fornece duas propriedades principais: InputParameters e OutputParameters. Cada uma dessas propriedades são representadas por uma coleção de somente leitura, onde cada parâmetro é representado por um objeto do tipo HttpParameter. Se analisarmos o modelo de classes, veremos que existem 16 versões da classe HttpOperationHandler, onde o que muda é a quantidade de parâmetros genéricos, que representarão os parâmetros de entrada da operação e um deles corresponderá ao resultado da mesma, e os handlers interferem indiretamente na criação e definição dos valores destas coleções.

Para exemplificar o seu uso, criaremos um operation handler que define algum header da requisição como sendo parâmetro para o método, entregando a informação de uma forma mais simples, deixando a extração da informação do header da requisição à cargo do handler. Abaixo vemos o serviço:

[ServiceContract]
public class ServicoDeTeste
{
    [WebGet]
    public HttpResponseMessage Informacoes(string codigo)
    {
        return new HttpResponseMessage()
        {
            StatusCode = HttpStatusCode.OK,
            Content = new ObjectContent<Informacao>(new Informacao(){ Codigo = codigo, Dado = “Alguma Info” })
        };
    }
}

Como podemos perceber, o método Informacoes espera um parâmetro chamado codigo, que o cliente não mandará como parte da Uri, mas sim como um header customizado na requisição. O nosso operation handler irá extrair esse header e irá “injetar” o valor no parâmetro esperado pelo método. Utilizaremos a versão da classe HttpOperationHandler que recebe dois parâmetros genéricos, onde o primeiro corresponde ao parâmetro de entrada, e o segundo, corresponde ao tipo do parâmetro que o handler está tratado.

Recebemos no construtor o nome do parâmetro que deve ser adicionado à coleção de InputParameters, e o nome do header que esse handler deverá extrair da requisição. O(s) parâmetro(s) do método OnHandle e o tipo de retorno são definidos de acordo com os parâmetros genéricos que foram definidos na construção da classe HttpOperationHandler. Esse método é disparado pelo runtime, e é onde devemos colocar o tratamento necessário. Para o exemplo, se não encontrarmos o header na requisição, uma exceção deverá ser disparada, informando que a requisição é inválida. Abaixo temos o código que corresponde a esta implementação:

public class HeaderAsParameterHandler : HttpOperationHandler<HttpRequestMessage, string>
{
    private readonly string headerName;

    public HeaderAsParameterHandler(string outputParameterName, string headerName)
        : base(outputParameterName)
    {
        this.headerName = headerName;
    }

    public override string OnHandle(HttpRequestMessage input)
    {
        if (!input.Headers.Contains(headerName))
            throw new HttpResponseException(HttpStatusCode.BadRequest);

        return input.Headers.GetValues(headerName).First();
    }
}

Da mesma forma que temos um handler para extrair o header da requisição e injetar na coleção de parâmetros, vamos exemplificar também a volta, ou seja, capturar alguma informação do resultado, para definirmos também como um header customizado na resposta. Agora herdaremos da classe HttpOperationHandler, e definiremos os parâmetros de entrada e saída como sendo do tipo HttpResponseMessage, pois ela é o alvo da alteração e também de onde extrairemos as informações.

public class OutputAsHeaderHandler : HttpOperationHandler<HttpResponseMessage, HttpResponseMessage>
{
    private readonly string headerName;
    private readonly Func<HttpResponseMessage, string> extractor;

    public OutputAsHeaderHandler(string headerName, Func<HttpResponseMessage, string> extractor)
        : base(“response”)
    {
        this.headerName = headerName;
        this.extractor = extractor;
    }

    public override HttpResponseMessage OnHandle(HttpResponseMessage input)
    {
        input.Headers.AddWithoutValidation(this.headerName, this.extractor(input));
        return input;
    }
}

Note que o construtor da classe acima, recebe o nome do header a ser inserido na resposta, e um delegate que permite ao consumidor da classe, extrair a informação do lugar que ele achar mais conveniente. No método OnHandle, capturamos a mensagem de resposta, invocamos o delegate e extraimos o valor do header e, finalmente, retornamos a mensagem já com o header devidamente adicionado.

Depois dos handlers criados, precisamos incorporá-los na execução. Para isso, vamos recorrer à uma outra classe, chamada de HttpOperationHandlerFactory. Esse classe fornece dois métodos, onde cada um corresponde à criação de handlers para requisição (OnCreateRequestHandlers) e outro para a resposta (OnCreateResponseHandlers). Como temos dois handlers, um que trata a requisição e outro que trata a resposta, então vamos sobrescrever ambos os métodos, assim como é mostrado abaixo:

public class HeaderMapperOperationHandlerFactory : HttpOperationHandlerFactory
{
    protected override Collection<HttpOperationHandler> OnCreateRequestHandlers(ServiceEndpoint endpoint, HttpOperationDescription operation)
    {
        var handlers = base.OnCreateRequestHandlers(endpoint, operation);
        handlers.Add(new HeaderAsParameterHandler(“codigo”, “CodigoDoCliente”));

        return handlers;
    }

    protected override Collection<HttpOperationHandler> OnCreateResponseHandlers(ServiceEndpoint endpoint, HttpOperationDescription operation)
    {
        var handlers = base.OnCreateResponseHandlers(endpoint, operation);

        handlers.Add(new OutputAsHeaderHandler(“CodigoDoCliente”,
            response => ((ObjectContent<Informacao>)response.Content).ReadAs().Codigo));

        return handlers;
    }
}

No método OnCreateRequestHandlers adicionamos a instância da classe HeaderAsParameterHandler, mapeando o header CodigoDoCliente para o parâmetro codigo. Já no método OnCreateResponseHandlers, criamos a instância da classe OutputAsHeaderHandler, informando no seu construtor o nome do header que desejamos que seja adicionado, e em seguida, um delegate que extrai o valor do header do corpo da mensagem.

Finalmente, tudo o que precisamos fazer é configurar o serviço para utilizar a factory de criação de operation handlers. Para isso, recorremos ao método genérico SetOperationHandlerFactory<T> da classe HttpHostConfiguration, onde informamos em seu tipo genérico T, o tipo da classe que criamos, que é a HeaderMapperOperationHandlerFactory. Abaixo temos um exemplo de como proceder com essa configuração:

protected void Application_Start(object sender, EventArgs e)
{
    var config =
        HttpHostConfiguration.Create().SetOperationHandlerFactory<HeaderMapperOperationHandlerFactory>();

    RouteTable.Routes.MapServiceRoute<ServicoDeTeste>(“teste”, config);
}

Depois de toda essa customização e configuração, tudo o que nos resta é realizar um teste. Ao efetuarmos uma requisição, vamos incluir o header customizado CodigoDoCliente, e o resultado deve voltar também com este mesmo header informado. Abaixo temos o log da requisição e da resposta que foi capturado pelo Fiddler:

Requisição
GET http://localhost:1989/teste/Informacoes HTTP/1.1
User-Agent: Fiddler
Host: localhost:1989
Accept: application/xml
CodigoDoCliente: 1291

Resposta
HTTP/1.1 200 OK
Server: ASP.NET Development Server/10.0.0.0
Date: Mon, 02 May 2011 02:09:22 GMT
X-AspNet-Version: 4.0.30319
CodigoDoCliente: 1291
Content-Length: 113
Cache-Control: private
Content-Type: application/xml; charset=utf-8
Connection: Close

<?xml version=”1.0″ encoding=”utf-8″?>
<Informacao>
  <Dado>Alguma Info Aqui</Dado>
  <Codigo>1291</Codigo>
</Informacao>

WCF Web API – Message Handlers

Seguindo as funcionalidades fornecidas pela WCF Web API, este artigo começa a abordar os pontos de estensibilidade que a mesma fornece, para que assim possamos interceptar vários estágios do processamento da mensagem no servidor, bem como do lado do cliente, caso estejamos utilizando a classe HttpClient para consumo de um serviço.

A Microsoft está construindo essa API em cima do próprio WCF, aproveitando a flexibilidade que ele fornece, para assim tornar a construção de um serviço que utiliza os princípios REST e, consequentemente, o protocolo HTTP, em algo muito mais simples. Já pudemos perceber isso nos artigos anteriores, e o fato da criação desta nova API, também há situações onde precisamos de algumas customizações, o que obriga a Microsoft a colocar nesta mesma API, recursos para que seja possível tal customização, sem complicar tanto como antes, afinal, estamos “um nível acima”.

Como sabemos, o WCF extrai os bytes correspondentes a solicitação no protocolo, utilizando toda sua infraestrutura, que a partir de agora, fica totalmente encapsulada nesta nova API. Depois de capturado, o WCF encaminha essa solicitação para esta nova layer, e a partir de agora inicia o um novo pipeline, que está dentro desta API. É este pipeline que possui vários pontos, e o primeiro deles é chamado de Message Handlers. Como o próprio nome diz, eles estão logo no primeiro estágio do pipeline, ou seja, independentemente de qual sua intenção para com o serviço, elas serão sempre serão executadas, a menos que haja algum critério que você avalie e rejeite a solicitação, o que proibirá o avanço do processamento para os próximos handlers.

Basicamente, esses handlers recebem a instância de uma classe do tipo HttpRequestMessage, que traz toda a solicitação do usuário, e retornam a instância da classe HttpResponseMessage, contendo a resposta gerada para aquela solicitação. E como já ficou subententido, podemos ter vários handlers adicionados ao pipeline, onde cada um deles pode ser responsável por executar uma tarefa distinta, como logging, autenticação, autorização, etc. A imagem abaixo ilustra esse fluxo:

A imagem se preocupa em mostrar a posição dos message handlers em relação ao serviço, mas ela está incompleta. Há ainda outros pontos entre o último message handler e a execução do serviço em si. O próximo passo é a criação da classe que representa o serviço, qual utilizamos uma implementação da interface IResourceFactory para customizar isso, ou até mesmo, acoplar um container de injeção de dependência, como vimos detalhadamente neste artigo.

A primeira ação para a criação que um message handler customizado, é herdar da classe abstrata DelegatingChannel. Essa classe recebe em seu construtor um objeto do tipo HttpMessageChannel. A finalidade deste objeto que é passado no construtor, é com o intuito de cada handler seja responsável por executar uma determinada tarefa, e depois passar para o próximo, ou seja, uma implementação do padrão Decorator. Antes de prosseguirmos com as explicações, vejamos um exemplo simples para logging:

public class LoggingMessageChannel : DelegatingChannel
{
    public LoggingMessageChannel(HttpMessageChannel innerChannel)
        : base(innerChannel) { }

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        return base.SendAsync(request, cancellationToken).ContinueWith(tr =>
        {
            var response = tr.Result;
            this.LogMessage(response);

            return response;
        }, cancellationToken);
    }

    private void LogMessage(HttpResponseMessage response)
    {
        Debug.WriteLine(
            string.Format(“Request:rn{0}rnResponse:rn{1}”,
                response.RequestMessage, response));
    }
}

Analisando o código acima, podemos perceber que sobrescrevemos o método SendAsync. Quando uma requisição chega para o serviço e temos um message handler adicionado, o método SendAsync dele é disparado. Note que como parâmetro recebemos uma instância da classe HttpRequestMessage, que como já está claro, reflete a requisição do cliente; em seguida, nós invocamos o método SendAsync da classe base (DelegatingChannel), e com isso, a requisição é encaminhada para o respectivo método no serviço que criamos, executando-o. O interessante é que o retorno deste método trata-se de uma instância da classe Task<HttpResponseMessage>, e com isso, permite a execução da tarefa para uma outra thread, sem bloquear a thread que iniciou a requisição, podendo esta ir atender uma outra requisição. Isso facilita bastante quando temos alguma operação de I/O, que exige um processamento mais complexo, o que resultará em mais tempo esperando pela resposta, e o uso do processamento assíncrono dará uma maior escalabilidade.

Este método está fazendo uso da classe Task<TResult>, que faz parte do modelo de programação assíncrona do .NET conhecido como TAP (Task Asynchronous Programming). Essa classe fornece um método chamado ContinueWith<TResult>, que me permite executar, também assincronamente, uma outra tarefa quando a tarefa principal for concluída, ou seja, no exemplo que temos acima, invocamos o método SendAsync da classe base, o método do serviço é disparado, e quando ele finalizar, irá executar a tarefa que colocamos dentro do método ContinueWith<TResult>, que nada mais é do que fazer o logging da mensagem de requisição e resposta.

Apesar de toda essa implementação, ela não funciona por si só. Precisamos adicioná-la à execução, e para isso, vamos recorrer ao objeto responsável pela configuração destes serviços, que é a classe HttpHostConfiguration. Essa classe possui um método chamado AddMessageHandlers, que permite informar um array de objetos do tipo Type, onde devemos mencionar as implementações (message handlers) da classe DelegatingChannel que desejamos adicionar à execução. Abaixo temos parte do arquivo Global.asax com a configuração para o serviço, e estamos fazendo uso de sua interface fluente para incrementarmos as customizações.

protected void Application_Start(object sender, EventArgs e)
{
    var config =
        HttpHostConfiguration.Create()
            .SetResourceFactory<MEFResourceFactory>()
            .SetErrorHandler<BadRequestErrorHandler>()
            .AddMessageHandlers(typeof(LoggingMessageChannel));

    RouteTable.Routes.MapServiceRoute<ServicoDeProspeccao>(“prospeccoes”, config);
}

Como já mostrei aqui, há também a possibilidade de utilizar essa mesma API em aplicações cliente, para o consumo destes tipos de serviços. E como era de se esperar, há também a possibilidade de fazer a interceptação da requisição e da resposta deste lado, e com isso, conseguir realizar verificações, consistências antes de enviar e/ou receber.

A classe HttpClient é a principal responsável por efetuar toda a coordenação das requisições e encaminhar as respectivas respostas para quem solicitou. Essa classe possui uma propriedade chamada Channel, que permite referenciar uma classe que herda da classe abstrata MessageProcessingChannel. Essa classe nos obriga a sobrescrever dois métodos, também autoexplicativos: ProcessRequest e ProcessResponse. O primeiro método é invocado momentos antes de enviar a requisição ao serviço, já o segundo, é invocado assim que a resposta volta. Abaixo temos uma implementação simples do mesmo:

public class LogProcessingChannel : MessageProcessingChannel
{
    public LogProcessingChannel(HttpMessageChannel innerChannel)
        : base(innerChannel) { }

    protected override HttpRequestMessage ProcessRequest(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        ConsoleLog(request);
        return request;
    }

    protected override HttpResponseMessage ProcessResponse(HttpResponseMessage response, CancellationToken cancellationToken)
    {
        ConsoleLog(response);
        return response;
    }
}

Depois disso, tudo o que precisamos fazer é adicioná-la à classe HttpClient, definindo-a na propriedade Channel. Só que o construtor recebe a instância de uma classe que corresponde ao canal final, que neste caso é a classe HttpClientChannel, que faz uso interno das classes de baixo nível do namespace System.Net (HttpWebRequest e HttpWebResponse). Abaixo temos um exemplo de como proceder com essa configuração:

using (HttpClient client = new HttpClient(“http://localhost:1989/prospeccoes/&#8221;))
{
    client.Channel = new LogProcessingChannel(new HttpClientChannel());

    using (HttpRequestMessage request2 =
        new HttpRequestMessage(HttpMethod.Get, “RecuperarEmpresasEmProspeccao”))
    {
        Console.WriteLine(client.Send(request2).Content.ReadAsString());
    }
}

Percebemos que há uma certa discrepância nos nomes, pois em alguns lugares vemos este recurso mencionado como message handlers e em outros como message channels. Eu estou utilizando o que imagino ser a mais recente, mas é importante salientar que este projeto ainda está em sua fase inicial, e pode haver mudanças significativas no decorrer de seu desenvolvimento.

WCF Web API – Tratamento de Erros

O WCF fornece um ponto de estensibilidade que nos permite centralizar o tratamento das exceções que eventualmente acontecem dentro do nosso serviço, e que já tive a oportunidade de falar disso aqui. Basicamente você recorre à uma interface chamada IErrorHandler, que quando acoplado ao runtime do WCF, qualquer exceção disparada será enviada à este handler, dando a oportunidade dele fazer o que achar necessário, incluindo o logging da mesma.

Com o WCF Web API, a Microsoft também está criando um ponto para permitir que se adicione um código customizado para interceptar as exceções que são disparados por estes tipos de serviços. Como já era de se esperar, essa classe implementa a interface IErrorHandler, e mais uma vez, a Microsoft cria “uma classe acima” para abstrair a complexidade do WCF.

Tudo o que precisamos fazer é criar uma classe que herda da classe abstrata HttpErrorHandler, sobrescrevendo os métodos OnHandleError e OnProvideResponse. O primeiro método retorna um valor boleano indicando se deve ou não abortar a sessão, caso exista uma. Já o segundo método, OnProvideResponse, recebe como parâmetro a exceção que foi disparada pelo serviço, e permite customizarmos o retorno para o cliente, como por exemplo, definir um status do HTTP coerente com o problema que ocorreu. O retorno deste método é representado por um objeto do tipo HttpResponseMessage, que define a mensagem que chegará ao cliente que solicitou. Abaixo temos um exemplo desta implementação:

public class BadRequestErrorHandler : HttpErrorHandler
{
    protected override bool OnHandleError(Exception error)
    {
        return true;
    }

    protected override HttpResponseMessage OnProvideResponse(Exception error)
    {
        HttpResponseException exception = error as HttpResponseException;               
        response = exception.Response;
        response.StatusCode = HttpStatusCode.BadRequest;

        return response;
    }
}

Uma vez criado o tratador de erros, precisamos adicioná-lo à execução, e para isso, vamos recorrer ao configurador desta nova API, que é a classe HttpHostConfiguration. Esse classe possui uma interface fluente, expondo um método genérico chamado SetErrorHandler<T>, onde o tipo T deve ser uma classe que herda de HttpErrorHandler.

protected void Application_Start()
{
    var config =
        HttpHostConfiguration.Create()
            .SetResourceFactory<MEFResourceFactory>()
            .SetErrorHandler<BadRequestErrorHandler>();

    RouteTable.Routes.MapServiceRoute<ServicoDeProspeccao>(“prospeccoes”, config);
}

Finalmente, o que precisamos fazer dentro do serviço quando há algum problema, é disparar uma exceção do tipo HttpResponseException, que por sua vez, retrata uma falha que houve durante a execução do mesmo.

Overview do Windows Identity Foundation

Os desafios de desenvolver aplicações que exigem um alto nível de segurança e as soluções oferecidas pela Microsoft para transformar essa tarefa em algo bem mais simples e reutilizável do que existe atualmente.

Com a finalidade de introduzir esse novo framework, coloquei as dificuldades que temos atualmente, a proposta e o modelo básico de objetos que o WIF fornece, em um artigo na edição 26 da revista MundoDotNet. Gostaria de agradecer ao Daniel de Oliveira pela oportunidade.