HttpClient na Portable Class Library

by Israel Aece 8. April 2013 22:19

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

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

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

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

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

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

Tags: , ,

.NET Framework | CSD

Geração de Documentação para ASP.NET WebApi

by Israel Aece 3. June 2012 15:35

Há algum tempo eu comentei aqui sobre REST e WSDL, onde a ideia era apontar a maneira de se trabalhar com serviços sem a necessidade de ter um schema que define o que serviço disponibiliza e, principalmente, toda a estrutura das mensagens (SOAP) que são trocadas entre as partes.

Mas é importante dizer que mesmo serviços baseados em REST, também precisam, de alguma forma, expor alguma espécie de documentação, para descrever as ações que as APIs estão disponibilizando aos consumidores, apontando o caminho (URI) até aquele ponto, método/verbo (HTTP), informações que precisam ser passadas, formatos suportados, etc.

A ideia é apenas ser informativo, ou seja, isso não será utilizado pelo cliente para a criação automática de uma proxy. Pensando nisso, a Microsoft incluiu no ASP.NET Web API a opção para gerar e customizar as documentações de uma API.

Mas a documentação é sempre exibida, na maioria das vezes, de forma amigável ao consumidor, para que ele possa entender cada uma das ações, suas exigências, para que ele possa construir as requisições da forma correta. Sendo assim, podemos na própria aplicação onde nós temos as APIs, criar um controller que retorna uma view (HTML), contendo a descrição das APIs que estão sendo hospedadas naquela mesma aplicação.

public class DeveloperController : Controller
{
    public ActionResult Apis()
    {
        var explorer = GlobalConfiguration.Configuration.Services.GetApiExplorer();

        return View(explorer.ApiDescriptions);
    }
}

Note que estamos recorrendo ao - novo - método GetApiExplorer, disponibilizado através da configuração global das APIs. Este método retorna um objeto que implementa a interface IApiExplorer, que como o próprio nome sugere, define a estrutura que permite obter a descrição das APIs. Nativamente já temos uma implementação chamada ApiExplorer, que materializa todoas as APIs em instâncias da classe ApiDescription, e uma coleção deste objeto é retornada através da propriedade ApiDescriptions, e que repassamos para que a view possa renderizar isso.

Na view, tudo o que precisamos fazer é iterar pelo modelo, e cada elemento dentro deste laço representa uma ação específica que está dentro da API. A classe que representa a ação, possui várias propriedades, fornecendo tudo o que é necessário para que os clientes possam consumir qualquer ums destas ações. Abaixo temos o código que percorre e exibe cada uma delas:

@model IEnumerable<System.Web.Http.Description.ApiDescription>

<body>
    @foreach (var descriptor in this.Model)
    {
        <ul>
            <li><b>@descriptor.HttpMethod - @descriptor.RelativePath</b></li>
            <li>Documentation: @descriptor.Documentation</li>

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

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

Ao acessar essa view no navegador, temos a relação de todas as ações que estão expostas pelas APIs. A visibilidade das ações é controlada a partir do atributo ApiExplorerSettingsAttribute, que possui uma propriedade boleana chamada IgnoreApi, que quando definida como True, omite a extração e, consequentemente, a sua visualização.

É importante notar que na imagem acima, estamos apresentando a propriedade Documentation. A mensagem que aparece ali é uma customização que podemos fazer para prover essa informação, extraindo-a de algum lugar. Para definir a descrição da ação, vamos criar um atributo customizado para que quando decorado no método, ele será extraído por parte da infraestrutura do ASP.NET, alimentando a propriedade Documentation. O primeiro passo, consiste na criação de um atributo para definir a mensagem:

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class ApiDocumentationAttribute : Attribute
{
    public ApiDocumentationAttribute(string message)
    {
        this.Message = message;
    }

    public string Message { get; private set; }
}

O próximo passo é decorá-lo em cada uma das ações que quisermos apresentar uma informação/descrição. A classe abaixo representa a nossa API, e o atributo recentemente criado foi decorado em todas as ações, descrevendo suas respectivas funcionalidades:

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

    [ApiDocumentation("Retorna um cliente pelo seu Id.")]
    public Cliente Get(int id)
    {
        //...
    }

    [ApiDocumentation("Inclui um novo cliente.")]
    public void Post(Cliente cliente)
    {
        //...
    }

    [ApiDocumentation("Exclui um cliente existente.")]
    public void Delete(int id)
    {
        //...
    }
}

Só que o atributo por si só não funciona. Precisamos de algum elemento para extrair essa customização que fizemos, e para isso, a temos uma segunda interface, chamada IDocumentationProvider, que fornece dois métodos com o mesmo nome: GetDocumentation. A diferença entre eles é o parâmetro que cada um deles recebe. O primeiro recebe um parâmetro do tipo HttpParameterDescriptor, o que permitirá descrever, também, cada um dos parâmetros de uma determinada ação. Já o segundo método, recebe um parâmetro do tipo HttpActionDescriptor, qual utilizaremos para extrair as informações pertinentes à uma ação específica.

public class ApiDocumentationAttributeProvider : IDocumentationProvider
{
    public string GetDocumentation(HttpParameterDescriptor parameterDescriptor)
    {
        return null;
    }

    public string GetDocumentation(HttpActionDescriptor actionDescriptor)
    {
        var attributes =
            actionDescriptor.GetCustomAttributes<ApiDocumentationAttribute>();

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

        return null;
    }
}

Aqui extraímos o atributo que criamos, e se ele for encontrado, retornamos o valor definido na propriedade Message. A ausência deste atributo, faz com que um valor nulo seja retornado, fazendo com que nenhuma informação extra seja incluída para a ação.

E, finalmente, para incluir o provedor de documentação ao runtime do ASP.NET, recorremos à configuração das APIs, substituindo qualquer implementação existente para este serviço, para o nosso provedor que extraí a documentação do atributo customizado.

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

Tags: , ,

ASP.NET | CSD

Recursos da Palestra do MVC Summit 2012

by Israel Aece 19. May 2012 20:49

 

Acabei de efetuar uma palestra no MVC Summit 2012. Entre os vários temas que foram discutidos sobre o desenvolvimento Web, eu falei sobre o ASP.NET Web API, que pode ser utilizado para a construção de serviços baseados em REST. Peço desculpas, mas infelizmente não houve tempo suficiente para abrir para perguntas e respostas, então para aqueles que gostaríamos de fazer algum questionamento, peço encarecidamente para que vocês coloquem nos comentários deste post, ou se desejarem, podem me contatar diretamente através da seção de contato.

Gostaria imensamente de agradecer a todos os presentes, e também ao Vinicius Quaiato, Andre Baltieri, Victor Cavalcante e ao Alexandre Tarifa por esta oportunidade. Para aqueles interessados, o download do projeto pode ser baixado clicando aqui, e se desejarem, aqui também estão os slides da apresentação.

Tags: , ,

CSD | General | WCF

Autenticação - Mix entre WebApi e Interfaces

by Israel Aece 16. April 2012 22:15

Para criar controllers que representem uma Web Api, trabalhamos de forma parecida com a criação de controllers para o ASP.NET MVC. Como trata-se apenas de um tipo específico de controller, podemos facilmente disponibilizar esta Api para consumo dentro da própria aplicação, para seu próprio consumo ou acesso por terceiros.

Apesar de suportado, podemos nos deparar com um problema específico ao hospedar a Api em uma aplicação que já possua uma interface com o usuário, e que controla a autenticação da mesma através do Forms Authentication.

Por padrão, as Web Apis possuem em sua rota um prefixo chamado /api/, mas independentemente disso, toda e qualquer requisição às ações (do Web Api ou não), serão interceptadas pelo módulo FormsAuthenticationModule, qual identifica se o usuário está ou não logado (baseando-se em um cookie), e se não estiver, irá redirecioná-lo para a página que login. Ele retorna para o navegador o código de 302 do HTTP, e quando ele (o navegador) receber este código, irá redirecionar para o endereço definido no header Location. Abaixo vemos o fluxo capturado pelo Fiddler:

A questão é que um serviço não espera que alguém se identifique "manualmente"; nem saberemos se estamos acessando-o via navegador ou através de uma outra aplicação. Sendo assim, a autenticação deve ser tratada pela própria requisição.

Remover ou "desligar" o FormsAuthenticationModule seria uma alternativa, mas isso faria com que a aplicação toda ficasse disponível para qualquer um acessar, inclusive de forma anônima. A solução mais simples seria separar fisicamente as aplicações, onde você teria uma para servir as aplicações que fornecem uma interface com o usuário, enquanto a outra, seria responsável apenas por hospedar as Apis que serão consumidas pelas outras aplicações (internas ou externas). Essa última opção, permitiria você tratar de forma independente cada uma delas, optando por qualquer meio de autenticação, sem que uma afeta no bom comportamento da outra.

Ainda há alguns truques que podemos recorrer para conseguir realizar esse mix de recursos em uma mesma aplicação, onde podemos identificar o código 302, e alterá-lo para 401 (Unauthorized), mas isso, tendo que escrever alguma customização, e em seguida, acoplar à execução para que ela funcione.

Tags: , ,

ASP.NET | Security

ASP.NET Web API: Implementação Assíncrona

by Israel Aece 12. March 2012 14:27

A Microsoft trabalha para que na próxima versão do C# e do VB.NET, eles já saiam com suporte para programação assíncrona. Como eu já havia mencionado em um post anterior, a ideia é facilitar a programação assíncrona, que não é nada trivial. A ideia é tornar a escrita de um código assíncrono, muito próximo a escrita de um código síncrono, e nos bastidores, o compilador faz grande parte do trabalho. Grande parte das funcionalidades do .NET Framework que já possuem suporte nativo ao consumo em formato assíncrono, foram readaptados para que assim, os desenvolvedores possam fazer uso dos recursos oferecidos pela linguagem para consumi-los.

Desta mesma forma, algumas tecnologias que dão suporte à construção de funcionalidades assíncronas, também sofreram adequações para este novo modelo. Para citar um caso, o WCF permite agora a construção de um serviço assíncrono de forma muito mais tranquila que antes, onde tínhamos que implementar um contrato assíncrono.

Já o ASP.NET merece algumas considerações: o ASP.NET Web Forms traz o conceito de páginas assíncronas, que também farão uso dos recursos das linguagens para implementa-las. O ASP.NET MVC possui uma classe chamada AsyncController, de qual herdamos e com pequenos ajustes, conseguimos ter ações sendo disparadas de forma assíncrona. Na próxima versão, o ASP.NET MVC também flexibilizará a criação das ações assíncronas, deixando, novamente, o trabalho árduo para o compilador.

Agora, ao utilizar o ASP.NET Web API, também podemos fazer com que as ações expostas pela API sejam processadas assincronamente. Como é a primeira versão desta tecnologia, a forma de escrevermos as ações assincronamente, é somente através dos recursos das linguagens. Só que antes de exibir como procedemos para criar o código assíncrono, vamos primeiramente criar a versão síncrona desta ação:

public class NoticiasRegionaisController : ApiController
{
    private const string ServicoDeNoticias =
        "http://localhost:1256/api/noticias/recuperar";

    [HttpGet]
    public IEnumerable<NoticiaDaRegiao> Recuperar()
    {
        return
            JsonArray.Parse
            (
                new WebClient().DownloadString(ServicoDeNoticias)
            ).ReadAsType<IEnumerable<NoticiaDaRegiao>>();
    }
}

Note que há um serviço chamado NoticiasRegionais, qual recorre à um outro serviço que é mais abrangente, para extrair as notícias de uma determinada região ou cidade. No interior do método Recuperar, propositalmente fazemos a chamada para o serviço e esperamos pelo resultado, que ao voltar, efetuamos o parser e, finalmente, convertemos para o formato esperado e retornamos ao cliente.

Ao rodar esse código, a requisição será bloqueada pelo runtime até que o resultado seja devolvido pelo serviço. Isso prejedica, e muito, a escalabilidade do serviço. O fato da thread ficar bloqueada enquanto espera pelo resultado do serviço, ela poderia estar atendendo à outras requisições, que talvez não exijam recursos de terceiros (I/O bound). O fato de disponibilizar a thread para que ela possa atender à outras requisições, farão com que elas não esperem por um - longo - tempo indeterminado, pois como dependemos do resultado de um terceiro, poderíamos arranjar muito trabalho para esta thread, até que ela precise retomar o trabalho da requisição anterior.

O gráfico abaixo apresenta algumas medições que foram feitas no serviço acima, que foi implementado de forma síncrona. Entre os contadores podemos visualizar a média do tempo gasto para que a requisição retorne, e além disso, a quantidade de requisições que o serviço de notícias regionais é capaz de atender por segundo.



Como mencionado acima, podemos implementar o controller da API de forma assíncrona, o que exigirá algumas mudanças, mas nada que faça com que seja necessário escrever e/ou gerenciar uma porção de código para garantir o assincronismo. Com isso, o primeiro detalhe a notar na escrita da ação assíncrona, é a exigência da keyword async, que faz parte do C#. Além disso, uma das grandes diferenças aqui, é com relação ao tipo de retorno da ação. No exemplo anterior, retornávamos um IEnumerable<T>, onde o tipo T é representado pela classe NoticiaDaRegiao. Aqui, ao invés disso, vamos retornar um Task<TResult>, onde TResult será definido com o mesmo tipo de retorno da ação síncrona, ou seja, IEnumerable<NoticiaDaRegiao>.

Internamente a implementação também mudará. Passamos a recorrer a classe HttpClient, que fará parte do .NET Framework, utilizado para consumir serviços REST, fornecendo vários facilitadores. Além disso, o fato de colocarmos a keyword async na assinatura do método, o compilador já nos obriga a definir o local que vamos aguardar pelo resultado, e para isso, utilizamos uma segunda keyword, chamada de await. No exemplo abaixo aguardamos a resposta voltar, e além disso, também invocamos a leitura do corpo da mensagem de forma assíncrona. Com isso, a ação que tínhamos foi rescrita e ficou da seguinte forma:

public class NoticiasRegionaisController : ApiController
{
    private const string ServicoDeNoticias =
        "http://localhost:1256/api/noticias/recuperar";

    [HttpGet]
    public async Task<IEnumerable<NoticiaDaRegiao>> Recuperar()
    {
        using (var client = new HttpClient())
            return await
                (await client.GetAsync(ServicoDeNoticias))
                .Content
                .ReadAsAsync<IEnumerable<NoticiaDaRegiao>>();
    }
}

Com isso, ao executarmos novamente os testes, agora contra o serviço implementado de forma assíncrona, veremos um ganho considerável, onde o tempo de resposta diminui e a quantidade de requisições atendidas por segundo aumenta. O gráfico abaixo já reflete essa mudança:

A implementação assíncrona trouxe um resultado interessante, aumentando a capacidade da aplicação de lidar com muitas requisições, e isso tende a aumentar dependendo das características do ambiente, como máquina, recursos, funcionalidades do serviço, etc.

Tags: , ,

ASP.NET | Async

Características do ASP.NET Web API

by Israel Aece 6. March 2012 08:07

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.

Tags: , , ,

ASP.NET | CSD

ASP.NET Web API - Overview

by Israel Aece 22. February 2012 21:36

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.

Tags: , ,

ASP.NET | CSD

WCF Web API agora é ASP.NET Web API

by Israel Aece 20. February 2012 08:39

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.

Tags: , , ,

ASP.NET | CSD | WCF

Powered by BlogEngine.NET 1.5.0.0
Theme by Mads Kristensen

Sobre

Meu nome é Israel Aece e sou especialista em tecnologias de desenvolvimento Microsoft, atuando como desenvolvedor de aplicações para o mercado financeiro utilizando a plataforma .NET. [ Mais ]

Twitter

Host