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

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

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

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

Health Monitoring no ASP.NET MVC

Há uma funcionalidade que foi criada no ASP.NET 2.0 chamada de Health Monitoring. Este recurso foi desenvolvido para servir como tratador de eventos que ocorrem em uma aplicação web. Utilizando um schema de configuração bastante elaborado, podemos customizar quais tipos de eventos queremos armazenar, onde será salvo, com qual periodicidade, intervalo, etc. Entre os tipos de eventos disponíveis, podemos citar: o sucesso e/ou falha no login, páginas não encontradas, erros não tratados, e assim por diante.

Apesar dela ter sido criada quando ainda não existia o ASP.NET MVC, isso não quer dizer que não pode utilizá-la com este tipo de projeto. O Health Monitoring trata-se de uma funcionalidade de “nível global”, onde você poderá utilizar em qualquer tipo de projeto ASP.NET (WebForms ou MVC). Sendo assim, para habilitar este recurso em uma aplicação MVC, basta realizar uma configuração no arquivo Web.config, conforme é mostrado abaixo. Note que estamos optando por armazenar os eventos no Event Log do Windows:

<system.web>
  <healthMonitoring enabled=”true”>
    <rules>
      <clear />
      <add
        name=”All Errors Default”
        eventName=”All Errors”
        provider=”EventLogProvider”
        profile=”Default”
        minInterval=”00:01:00″/>
    </rules>
  </healthMonitoring>
</system.web>

Vale lembrar que exceções não tratadas são catalogadas como esperado, porém o ASP.NET MVC possui um atributo chamado HandleErrorAttribute, que tem a finalidade de interceptar as requisições para este atributo quando uma exceção não tratada ocorre dentro da ação que está sendo requisitada, e ele, por sua vez, reencaminha a requisição para uma View padrão chamada Error, para exibir uma mensagem amigável ao usuário.

Para garantir que esta exceção também seja catalogada pelo Health Monitoring, é necessário criarmos um evento customizado, herdando da classe WebRequestErrorEvent. Essa classe será utilizada por uma customização da classe HandleErrorAttribute, onde invocaremos dentro do método OnException, o método Raise da classe WebRequestErrorEvent, passando a ele a exceção capturada pelo ASP.NET. Com isso, todas as exceções não tratadas serão encaminhadas para o atributo CatalogarErroNoHealthMonitoring, catalogadas pelo Health Monitoring e, finalmente, o usuário será redirecionado para a View Error (padrão do MVC).

public class CatalogarErroNoHealthMonitoring : HandleErrorAttribute
{
    public override void OnException(ExceptionContext filterContext)
    {
        base.OnException(filterContext);
        new DescricaoDeErro(this, filterContext.Exception).Raise();
    }
}

public class DescricaoDeErro : WebRequestErrorEvent
{
    private static readonly int eventCode = WebEventCodes.WebExtendedBase + 1;

    public DescricaoDeErro(object eventSource, Exception exception)
        : base(“Exceção Não Tratada”, eventSource, eventCode, exception) { }
}

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

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

Autenticação – Mix entre WebApi e Interfaces

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.

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

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&#8221;;

    [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&#8221;;

    [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.

Características do ASP.NET Web API

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

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

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

Model Binding

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

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

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

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

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

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

[ Via Formulário ]

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

Nome=Israel&Email=ia@israelaece.com

[ Via JSON ]

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

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

[ Via XML ]

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

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

Validações

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

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

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

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

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

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

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

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

[ Via JSON ]

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

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

[ Via XML ]

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

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

Tratamento de Erros

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

Tratar as exceções in-place pode não é uma saída elegante, devido a redundância de código. Para facilitar, podemos centralizar o tratamento em nível de aplicação, o que permitirá com que qualquer exceção não tratada no interior da ação, será capturada por este tratador, que por sua vez, analisará o erro ocorrido, podendo efetuar algum tipo de logging e, finalmente, encaminhar o problema ao cliente. É neste momento que podemos efetuar alguma espécie de tradução, para tornar a resposta coerente ao que determina os códigos do HTTP, como por exemplo: se algum erro relacionado à autorização, devemos definir como resposta 403 (Forbidden); já se algum informação está faltante (assim como vimos no exemplo acima), devemos retornar (400) BadRequest; já se o registro procurado não foi encontrado, ele deverá receber o código 404 (NotFound), e assim por diante.

Da mesma forma que vimos acima, aqui também vamos recorrer a criação de um filtro customizado para centralizar a tradução de algum problema que acontecer. Só que neste caso, temos uma classe abstrata chamada de ExceptionFilterAttribute, que já fornece parte da infraestrutura necessária para o tratamento de erros que ocorrem, e é equivalente ao atributo HandleErrorAttribute que temos no ASP.NET MVC. Tudo o que precisamos fazer aqui é sobrescrever o método OnException e definir toda a regra de tradução necessária. Abaixo um exemplo simples de como proceder para realizar esta customização:

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

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

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

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

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

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

Injeção de Dependências

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

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

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

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

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

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

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

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

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

        return null;
    }

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

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

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

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

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

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

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

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

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

ASP.NET Web API – Overview

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

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

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

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

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

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

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

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

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

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

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

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

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

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

WCF Web API agora é ASP.NET Web API

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

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

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

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

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

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

Habilitando JSONP no ASP.NET MVC

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

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

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

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

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

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

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

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

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

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.