Registrando Recursos para Eliminação

Apesar do ASP.NET Web API possui um mecanismo que nos permite estender e acoplar algum gerenciador de dependências, temos a possibilidade de registrar um determinado objeto para que ele seja descartado quando a requisição for completamente atendida.

É muito comum em aplicações Web criar um determinado objeto e querer mante-lo por toda a requisição, e em vários momentos e locais por onde a requisição trafega, podemos recuperar o referido objeto e reutiliza-lo para fazer alguma atividade complementar. Bancos de dados, loggers, entre outros, são exemplos de recursos que são úteis durante a vida da requisição dentro do pipeline onde ela está sendo processada.

A classe HttpRequestMessage possui uma propriedade chamada Properties (IDictionary<string, object>) que permite catalogarmos diversas informações inerentes à requisição, bem como recursos que podem ser (re)utilizados durante todas as etapas da execução. Uma vez adicionados, eles podem ser extraídos em qualquer momento no futuro que venha a precisar deles, mesmo que seja em outras camadas.

A dificuldade não é adicionar, mas saber o momento certo de descarta-lo. Simplesmente adicionar o recurso no dicionário não é suficiente para o ASP.NET Web API fazer a eliminação correta do mesmo. A Microsoft disponibilizou um método de extensão chamado RegisterForDispose, exposto pela classe HttpRequestMessageExtensions. Devemos utilizar este método para indicar explicitamente ao ASP.NET Web API que aquele objeto deve ser descartado no final da requisição. E, como era de se esperar, este método recebe objetos que implementam obrigatoriamente a interface IDisposable.

public class LoggerHandler : DelegatingHandler
{
    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var logger = new TextLogger(@”C:TempLog.txt”);
        request.RegisterForDispose(logger);
        request.Properties.Add(“TextLogger”, logger);

        return base.SendAsync(request, cancellationToken).ContinueWith(tr =>
        {
            var response = tr.Result;

            logger.Write(“Request: ” + request.ToString()).ContinueWith(_ =>
                logger.Write(“Response: ” + response.ToString())).Wait();

            return response;
        }, cancellationToken);
    }
}

Curiosamente o método RegisterForDispose também recorre a propriedade Properties da classe HttpRequestMessage para acomodar os objetos que serão descartados quando a mesma também for removida. Caso encontre um momento mais oportuno para fazer o descarte, podemos recorrer ao método (também de extensão) chamado DisposeRequestResources para antecipar essa rotina, ou ainda, se preferir inspecionar os objetos marcados, pode-se utilizar o método GetResourcesForDisposal para isso.

Outro uso para o que vimos aqui é quando você opta por interceptar a criação do controller (através da implementação da interface IHttpControllerActivator), onde o mesmo pode necessitar de recursos em seu construtor e que sejam necessários serem marcados para descarte no término da requisição.

Anúncios

Externalizando a Emissão de Tokens

No artigo anterior eu mostrei como emitir tokens para aplicações que consomem APIs. Como podemos notar naquele artigo, o mesmo projeto e, consequentemente, a mesma aplicação, é responsável por gerenciar, validar e autenticar os usuários. Enquanto isso é o suficiente para aplicações pequenas, pode não ser muito produtivo e de fácil gerenciamento quando temos outras aplicações que também precisam de autenticação.

Se for analisar mais friamente, talvez até quando temos uma pequena aplicação, seja mais viável manter uma segunda aplicação que seria responsável por todo o processo de autenticação, e a medida em que novos serviços são criadas, eles confiariam neste autenticador que já está pronto.

O que faremos neste artigo é separar o código que é responsável por validar e emitir os tokens da aplicação (API) que consome o token e libera o acesso aos recursos mediante a validade do mesmo. A imagem abaixo ilustra o fluxo que será executado a partir de agora:

Note que o Autenticador é responsável por validar e emitir o token para o usuário que se identifica para ele; o Serviço é onde está hospedada a aplicação que irá consumir o token. Basicamente temos que dividir aquele código do outro artigo em dois projetos, ou seja, não há necessidade nem de por nem tirar qualquer linha de código. O serviço passa a ter apenas o código que pluga no pipeline de execução a validação do token:

public void Configuration(IAppBuilder app)
{
var config = new HttpConfiguration();

    ConfigureOAuth(app);
WebApiConfig.Register(config);

    app.UseWebApi(config);
}

private static void ConfigureOAuth(IAppBuilder app)
{
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}

O restante do código, que é onde configuramos a validação do usuário, é movido para a aplicação chamada de Autenticador. A aplicação cliente passa a apontar para os endereços, agora em diferentes locais, para emitir o token em um deles, e passar o token gerado para a aplicação.

using (var client = new HttpClient())
{
using (var tokenResponse = await
client.PostAsync(“http://www.autenticador.com.br:81/issuer/token“, CreateContent()))
{

        using (var requestMessage =
new HttpRequestMessage(HttpMethod.Get, “http://www.servico.com.br:82/api/Test/GetData“))
{

}
}
}

Por fim, se rodarmos ele não irá funcionar. O motivo é que o token é protegido utilizando as chaves que estão no elemento machineKey dentro do arquivo Web.config. Se as aplicações (Autenticador e Serviço) tiverem chaves diferentes, então o token gerado pelo Autenticador não será possível ser consumido pelo Serviço. O que precisamos fazer aqui é gerar uma chave e copiar a mesma para as duas aplicações. Para gerar essas chaves, podemos recorrer à um recurso que temos no próprio IIS (mais detalhes aqui). Abaixo tem o arquivo Web.config já com esta configuração realizada. Vale lembrar que o tamanho das chaves foi reduzido por questões de espaço.

validationKey=”D2E9D0907…47BC9F8A598″
decryptionKey=”7278E7F93…658B70DE07E21CF”
validation=”SHA1″
decryption=”AES” />

Depois desta informação espelhada em ambas as aplicações, já é possível uma das aplicações gerar o token e a outra consumi-lo.

Emissão de Tokens no ASP.NET Web API

Em aplicações Web é comum o cliente precisar se autenticar para ter acesso à determinados recurso da aplicação. Quando o usuário se identifica para a aplicação, e se ela validar o mesmo, gravamos um cookie no navegador para que ele possa manter a autenticação válida durante a sua navegação (e enquanto o mesmo não expirar), evitando assim que ele tenha que se (re)autenticar toda cada vez que quer acessar um recurso protegido.

Quando estamos trabalhando com serviços, onde são outros sistemas que os consomem, precisamos autenticar a aplicação/usuário para que ele possa acessar os recursos que eles disponibilizam. Enquanto aplicações Web (que possuem uma interface) mantém um cookie, os serviços lidam de uma forma diferente, ou seja, recorrem à tokens para autenticar e identificar o chamador, e a partir deste momento, o mesmo deverá apresentar o token a cada vez que deseja acessar algum dos recursos expostos pelo serviço.

Ao invés de termos controllers e actions que servirão para esse tipo de atividade, podemos (e devemos) recorrer à alguns recursos que a própria tecnologia nos oferece. Quando optamos por hospedar e executar o ASP.NET Web API no OWIN, ele já traz alguns middlewares para autenticação, e entre eles, a possibilidade de utilizar o a tecnologia OAuth2 para guiar todo o processo de autenticação. O primeiro passo é instalar os seguintes pacotes (via Nuget): Microsoft.Owin.Host.SystemWeb, Microsoft.AspNet.WebApi.Owin e Microsoft.Owin.Security.OAuth.

Esses pacotes irão disponibilizar um conjunto de classes para trabalharmos com o OWIN dentro do ASP.NET Web API. O primeiro passo é realizar duas configurações dentro da classe Startup (exigência do OWIN): um middleware que será responsável pela geração de tokens e o outro que terá o papel de validar os tokens apresentados para o serviço antes deles serem executados.

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        var config = new HttpConfiguration();

        ConfigureAuthentication(app);
        WebApiConfig.Register(config);
        app.UseWebApi(config);
    }

    private static void ConfigureAuthentication(IAppBuilder app)
    {
        app.UseOAuthAuthorizationServer
        (
            new OAuthAuthorizationServerOptions()
            {
                AccessTokenExpireTimeSpan = TimeSpan.FromHours(1),
                AllowInsecureHttp = true,
                TokenEndpointPath = new PathString(“/issuer/token”),
                Provider = new OAuthAuthorizationServerProvider()
                {
                    OnValidateClientAuthentication = async ctx =>
                    {
                        await Task.Run(() => ctx.Validated());
                    },
                    OnGrantResourceOwnerCredentials = async ctx =>
                    {
                        await Task.Run(() =>
                        {
                            if (ctx.UserName != “Israel” || ctx.Password != “12345”)
                            {
                                ctx.Rejected();
                                return;
                            }

                            var identity = new ClaimsIdentity(
                                new[] {
                                        new Claim(ClaimTypes.Name, ctx.UserName),
                                        new Claim(ClaimTypes.Role, “Admin”)},
                                ctx.Options.AuthenticationType);

                            ctx.Validated(identity);
                        });
                    }
                }
            }
        );

        app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
    }
}

Através do método UseOAuthAuthorizationServer realizamos as configurações do emissor de tokens. As propriedades expostas pela classe OAuthAuthorizationServerOptions nos permite customizar diversas informações críticas para o processo de emissão. Entre elas temos o endpoint em que os clientes deverão visitar para gerar o token, o tempo de expiração para cada token e, por fim, e não menos importante, o provider. É o provider que podemos customizar a validação do usuário, verificando se ele é ou não um usuário válido. Para essa customização, basta herdar da classe OAuthAuthorizationServerProvider e sobrescrever (se assim desejar) diversos métodos para controlar todos os eventos gerados pelo protocolo OAuth2.

Para o exemplo estou optando por definir a propriedade AllowInsecureHttp como true, evitando a necessidade de expor o serviço sobre HTTPS, mas é importante que isso seja reavaliado antes de colocar em produção. Outro detalhe é que estou definindo, em hard-code, o nome e senha válidos; em um cenário real, é neste momento que deveríamos recorrer à algum repositório de usuários e validar se ele existe lá.

Depois de configurado o emissor de tokens, o middleware que habilitamos através do método UseOAuthBearerAuthentication é o responsável por validar os tokens que são enviados nas futuras requisições e identificar se eles são ou não válidos.

O fluxo necessário para a geração do token e para envio subsequente em novas requisições é bastante simples. Basta realizar um post para o endereço configurado na propriedade TokenEndpointPath, passando no corpo da mensagem três parâmetros: grant_type, username e password. Esses parâmetros serão utilizados pelo protocolo OAuth para validar o usuário e gerar o token caso ele seja válido. O parâmetro grant_type indica ao OAuth o tipo de autenticação que queremos fazer; neste caso o valor deverá ser “password”. Já os parâmetros username e password são autoexplicativos.

Se o usuário for válido, então o resultado será devolvido através do corpo da mensagem de resposta, formatado em JSON. Abaixo está um exemplo da resposta, mas o token foi reduzido por questões de espaço. O seu tamanho é muito maior que isso.

{
    “access_token”:”CPIA6Ha-9Bg2Yh8PZD-7Terzl9At…..UBp-WlpkNYn5ioD85U”,
    “token_type”:”bearer”,
    “expires_in”:3599
}

Agora compete à aplicação que consome este serviço armazenar o token e embutir nas futuras requisições. A exigência do protocolo é que o token seja incluído através do header Authorization na requisição, especificando além do token, também o seu tipo, que neste caso é bearer, e ele também é devolvido pelo emissor do token.

Para realizarmos os testes, vamos criar um controller e expor um método para que seja consumido apenas por usuários que estejam devidamente autenticados. Para isso, basta decorar o controller ou a ação com o atributo AuthorizeAttribute, conforme podemos visualizar no código abaixo:

public class TestController : ApiController
{
    [HttpGet]
    [Authorize]
    public string GetData()
    {
        return “Testing…”;
    }
}

Para exemplificar o consumo por parte do cliente, estou utilizando uma aplicação console para solicitar a emissão do token, e na sequência invocamos o método GetData da API passando o token como header, conforme o fluxo que foi explicado acima.

private async static void Invoke()
{
    using (var client = new HttpClient())
    {
        using (var tokenResponse = await client.PostAsync(“http://localhost:1195/issuer/token&#8221;, CreateContent()))
        {
            var tokenBody = await tokenResponse.Content.ReadAsStringAsync();
            dynamic parsedTokenBody = JsonConvert.DeserializeObject(tokenBody);

            using (var requestMessage = new HttpRequestMessage(HttpMethod.Get, “http://localhost:1195/api/Test/GetData&#8221;))
            {
                requestMessage.Headers.Authorization =
                    new AuthenticationHeaderValue(
                        parsedTokenBody.token_type.ToString(),
                        parsedTokenBody.access_token.ToString());

                using (var responseMessage = await client.SendAsync(requestMessage))
                {
                    var responseBody = await responseMessage.Content.ReadAsStringAsync();

                    Console.WriteLine(responseBody);
                }
            }
        }
    }
}

private static FormUrlEncodedContent CreateContent()
{
    return new FormUrlEncodedContent(new[]
    {
        new KeyValuePair<string, string>(“grant_type”, “password”),
        new KeyValuePair<string, string>(“username”, “Israel”),
        new KeyValuePair<string, string>(“password”, “12345”)
    });
}

Um detalhe importante é que dentro do controller, podemos fazer o (down)casting da propriedade User e chegar na instância da classe ClaimsPrincipal e, consequentemente, acessar o conjunto de claims que foi gerada pelo emissor do token para este usuário. Como disse anteriormente, claims estão em todo lugar.

((ClaimsPrincipal)this.User).Claims.First().Value;

Conversão de Datas em Ações da API

Há momentos em que precisamos parametrizar as ações de controllers com outros tipos de dados que vão além de inteiros e strings, e sem ainda falar de tipos de complexos, o tipo DateTime pode ser uma necessidade muito comum em alguns casos. O problema é que este tipo de dado possui diversas formatações e sua validade varia de acordo com a cultura contra qual ele está sendo validado.

Sendo assim, podemos nos deparar com alguns problemas, onde apesar de ser uma data válida se considerarmos o formato brasileiro, ela pode ser considerada inválida pela API que utiliza o formato americano para tratar e vice versa. Mesmo que a cultura da aplicação esteja definida para a região correta, os componentes internos do ASP.NET Web API não são capazes de entender o formato da data que o cliente deve passar. Se considerarmos a data 20 de dezembro de 2015, 20/12/2015 é um formato válido para nós mas inválido para os Estados Unidos; já a data 12/20/2015 é o contrário.

Para especificar o formato exato para realizar a conversão, podemos criar um model binder específico para a data, e no interior do mesmo fazer a formatação desejada para todas as datas que são recebidas em parâmetros dos serviços. Abaixo está o exemplo de como poderíamos codificar este formatador:

public class CustomDateTimeModelBinder : IModelBinder
{
    private readonly string format;

    public CustomDateTimeModelBinder(string format)
    {
        this.format = format;
    }

    public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
    {
        var date = bindingContext.ValueProvider.GetValue(bindingContext.ModelName).AttemptedValue;

        if (string.IsNullOrWhiteSpace(date))
            return false;

        bindingContext
            .ModelState
            .SetModelValue(
                bindingContext.ModelName,
                bindingContext.ValueProvider.GetValue(bindingContext.ModelName));

        DateTime result = DateTime.MinValue;

        if (DateTime.TryParseExact(date, format, Thread.CurrentThread.CurrentCulture, DateTimeStyles.None, out result))
        {
            bindingContext.Model = result;
            return true;
        }

        bindingContext.ModelState.AddModelError(
            bindingContext.ModelName,
            string.Format(“”{0}” is invalid.”, bindingContext.ModelName));

        return false;
    }
}

Por fim, basta acoplá-lo à execução e indicar ao ASP.NET Web API que ele trata e valida o tipo DateTime. Para isso, basta utilizar a configuração do serviço para inclui-lo e as requisições que mandarem a data no formato especificado em seu construtor serão corretamente convertidas em DateTime respeitando o dia, mês e ano.

config.BindParameter(typeof(DateTime), new CustomDateTimeModelBinder(“dd/MM/yyyy”));

Protegendo Formulários com reCaptcha

É comum termos formulários disponíveis em áreas públicas de sites. Esses formulários servem para que os usuários possam, geralmente, realizar cadastros, assinar newsletters, etc. Por estar público me refiro à não ser necessário se identificar para o site (login se senha) para poder ter acesso aquele recurso, e como já era de se esperar, alguém de má fé (ou não) pode começar a criar robôs para realizar diversas requisições de forma automática ao site, simulando ser um usuário e, consequentemente, tendo acesso ao recurso que é oferecido após o preenchimento do formulário.

Desconsiderando quem utiliza de má fé, quando clientes começam a desenvolver robôs para acessar um determinado recurso, é provável que seja o momento de criar algum serviço (API) para consumo direto por outros sistemas. Isso vai ao contrário do escopo deste artigo, ou seja, veremos aqui como fazer uso do reCAPTCHA, que é uma tecnologia oferecida gratuitamente pelo Google para proteger aplicações Web de robôs que tentam se passar por pessoas para acessar os recursos.

O primeiro passo para fazer uso, é cadastrar a aplicação (necessário uma conta do Google para isso). Ao fazer isso, um par de chaves será criado para fazermos uso em nossa aplicação. Abaixo está as configurações da aplicação de criei para o teste. A primeira chave (Site Key) é embutida no próprio HTML da aplicação, enquanto a segunda (Secret Key) deve ser mantida em sigilo e será utilizada para validar a resposta que o usuário informou, e isso será feito através do C# neste exemplo.

Para exibir o controle que faz toda a inteligência, basta adicionarmos a referência para um arquivo Javascript e adicionar um DIV no HTML, posicionando-o no local da tela que deseja que ele seja exibido. Repare que há um atributo chamado data-sitekey, que é onde colocaremos o Site Key gerado para a nossa aplicação. O HTML gerado deve ficar parecido com o código abaixo (estou omitindo o restante por questões de espaço e relevância):

<html>
<head>
    https://www.google.com/recaptcha/api.js
</head>
<body>
    <form>
       

 </form>
</body>

Ao executar a aplicação, teremos o formulário como vemos abaixo. Ao clicar no checkbox, uma pequena janela se abre para informar o texto que é apresentado. Quando você digita e clica no botão Confirmar, o componente gera um novo campo chamado g-recaptcha-response, que será submetido para o servidor e lá é onde iremos verificar junto ao Google se o que foi digitado está correto ou não. As imagens abaixo ilustram as três etapas antes de submeter o formulário para o servidor:



Agora chega o momento de validarmos o que foi digitado pelo usuário do lado do servidor. Essa validação garantirá que os dados digitados são válidos e correspondem a chave gerada para a nossa aplicação. O Google fornece uma URL que permite fazermos uma requisição (GET), passando alguns parâmetros para a validação, sendo eles: secret, response e remoteip. O primeiro é a chave privada (Secret Key) que foi gerada para nosso site; o segundo parâmetro, response, é todo o conteúdo postado no campo g-recaptcha-response e, finalmente, o terceiro parâmetro é o endereço IP do cliente, mas trata-se de um parâmetro opcional.

Para realizar esta requisição, vamos utilizar a classe HttpClient de forma assíncrona para termos uma melhor performance no servidor. O resultado, codificado em JSON, pode ser convertido em um objeto para manipular de forma mais intuitiva no C#.

Basicamente estamos gerando a URL de acordo com os parâmetros exigidos, e através de uma requisição GET, vamos até o Google para validação do valor informado pelo usuário. Se o resultado for positivo (success = true), então seguimos adiante para armazenar o e-mail em nossa base de dados. Por questões de simplicidade, não estou recuperando os possíveis erros que podem acontecer durante a validação pelo Google, mas a resposta da requisição também contempla uma coleção chamada error-codes, que como o próprio nome diz, retorna os erros encontrados.

public class NewsletterController : Controller
{
    private const string ChaveSecreta = “6LfJqw………….06U1uL”;
    private const string UrlDeValidacao =
        “https://www.google.com/recaptcha/api/siteverify?secret={0}&response={1}&remoteip={2}”;

    [HttpPost]
    public async Task<ActionResult> Assinar(FormCollection fc)
    {
        var email = fc[“email”];
        var respostaDoUsuario = fc[“g-recaptcha-response”];
        var houveFalha = !(await ValidarCaptcha(respostaDoUsuario));

        if (!houveFalha)
        {
            //Incluir E-mail na Base de Dados
        }

        ViewBag.HouveFalha = houveFalha;
        return View();
    }

    private async Task<bool> ValidarCaptcha(string respostaDoUsuario)
    {
        var url =
            string.Format(UrlDeValidacao, ChaveSecreta, respostaDoUsuario, Request.UserHostAddress);

        using (var cliente = new HttpClient())
        {
            var resposta = await cliente.GetAsync(url);
            var resultado = await resposta.Content.ReadAsAsync<Resultado>();

            return resultado.Success;
        }
    }
}

public class Resultado
{
    public bool Success { get; set; }
}

Mantendo objetos durante a requisição

Quando a requisição chega em um determinado serviço ela tem como alvo executar uma determinada tarefa e devolver um resultado. Antes da requisição chegar ao seu destino, ela passa por algumas etapas, e depois que a tarefa é de fato executada, outras etapas também são executadas antes de devolver a resposta para o cliente.

A manutenção de estado de objetos muitas vezes se faz necessária, pois ele servirá como uma espécie de contexto que viverá do início ao fim da requisição. Um exemplo comum disso é quando temos um objeto que gerencia uma transação (Unit of Work), e com ele seria possível envolver tudo o que acontece na requisição em um mesmo contexto transacional, pois se no fim do processamento alguma falha ocorrer, será possível reverter tudo o que fora realizado até ali.

Como sabemos, a ação dentro do controller de fato é a tarefa que queremos executar, mas o que ocorre antes e depois (geralmente são atividades de cross-cutting) também pode ser envolvido para contextualizar todo o processo. Este artigo exemplifica em como implementar e gerenciar isso no ASP.NET Web API. Para o exemplo, vamos ter um recurso que interceptará vários estágios da requisição, e logará todos os passos por onde ela passou. A interface IRequestTracking servirá como base para qualquer tipo de rastreador de requisições. A classe que está a seguir (MemoryRequestTracking) é uma implementação dela, que basicamente armazena os passos em uma coleção e persiste no Trace.

[InheritedExport]
public interface IRequestTracking
{
    Guid RequestId { get; }

    IEnumerable<string> Steps { get; }

    void AddStep(string message);

    void Flush();
}

public class MemoryRequestTracking : IRequestTracking
{
    private readonly IList<string> steps;

    public MemoryRequestTracking()
    {
        this.RequestId = Guid.NewGuid();
        this.steps = new List<string>();
    }

    public void AddStep(string message)
    {
        this.steps.Add(
            string.Format(“{0:dd/MM/yyyy HH:mm:ss} – Id: {1} – {2}”,
                DateTime.Now, this.RequestId, message));
    }

    public Guid RequestId { get; private set; }

    public IEnumerable<string> Steps { get { return this.steps; } }

    public void Flush()
    {
        foreach (var step in this.Steps)
            Trace.WriteLine(step);
    }
}

O ASP.NET Web API já traz nativamente uma espécie de repositório de dependências, que durante o runtime, a medida em que recursos vão sendo solicitados, esse repositório é consultado para resolver a(s) dependência(s), retornando uma implementação concreta do recurso solicitado. Felizmente podemos customizar esse repositório e utilizar algum container de injeção de dependências (DI) de sua preferência para auxiliar no gerenciamento e na criação das instâncias.

A customização resume em se criar uma classe que implemente a interface IDependencyResolver, e através dos métodos autoexplicativos, retornamos os recursos solicitados. É no interior desta classe que, eventualmente, podemos utilizar um container de DI, e para este exemplo estou utilizando o MEF (Managed Extensibility Framework).

public class MefResolver : IDependencyResolver
{
    private readonly CompositionContainer container;

    public MefResolver()
        : this(new CompositionContainer(
            new AssemblyCatalog(Assembly.GetExecutingAssembly()))) { }

    public MefResolver(CompositionContainer container) { this.container = container; }

    public IDependencyScope BeginScope() { return new MefResolver(); }

    public object GetService(Type serviceType)
    {
        return GetServices(serviceType).FirstOrDefault();
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        var services = this.container.GetExports(serviceType, null, null);

        return !services.Any() ? Enumerable.Empty<object>() : services.Select(s => s.Value);
    }

    public void Dispose() { this.container.Dispose(); }
}

Basicamente a classe acima recebe em seu construtor o container que servirá como “base de dados” das dependências e resolverá as solicitações procurando por implementações dentro do próprio assembly que está em execução. Só que a classe por si só não funcionará, pois precisamos acoplá-la à execução, e para isso, devemos configurar definer a instância dela na propriedade DependencyResolver exposta pela classe HttpConfiguration, assim como é mostrado abaixo:

public static void Register(HttpConfiguration config)
{
    config.DependencyResolver = new MefResolver();

    //outras configurações
}

Agora que toda a configuração já está realizada, precisamos começar a adicionar os passos nos locais que desejarmos interceptar. Como falei anteriormente, vamos querer acessar o rastreador em várias etapas diferentes, e felizmente, o ASP.NET Web API e seu container de DI são capazes de criar e disponibilizar a instância quando precisarmos, e isso quer dizer que poderemos acessar esses recursos não só no interior do controller, mas também em filtros, handlers, formatters, etc.

O gestor de dependência que temos (MefResolver) é construído no ínicio da requisição e é adicionado às propriedades da classe HttpRequestMessage, que nada mais é do que um dicionário de dados e mantém uma relação de objetos que são utilizados durante a requisição. Como o gestor de dependência é criado para cada requisição, então os objetos que são criados a partir dele também serão mantidos.

O primeiro lugar que vamos acessar é dentro de um filtro customizado. Note que a classe base ActionFilterAttribute fornece métodos para interceptar o antes e depois da ação executada.

public class RequestTrackingFilterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        ((IRequestTracking)actionContext
            .Request
            .GetDependencyScope()
            .GetService(typeof(IRequestTracking)))
            .AddStep(“OnActionExecuting”);

        base.OnActionExecuting(actionContext);
    }

    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
    {
        ((IRequestTracking)actionExecutedContext
            .Request
            .GetDependencyScope()
            .GetService(typeof(IRequestTracking)))
            .AddStep(“OnActionExecuted”);

        base.OnActionExecuted(actionExecutedContext);
    }
}

Graças à um método de extensão chamado GetDependencyScope atribuído a classe HttpRequestMessage, é fácil chegarmos à esse gestor e solicitar o recurso que queremos. Para expressar o recurso que queremos, basta informar a interface IRequestTracking, que ele devolverá a instância criada ou criará uma nova caso ela ainda não exista. Depois basta fazer a conversão explícita (casting) e acessar os seus membros.

Já dentro do controller, a forma de chegar até este recurso é bem semelhante. Note que no código abaixo temos o rastreador declarado como um campo na classe, e como ele está decorado com o atributo ImportAttribute (do MEF), o container resolve a dependência e injeta a instância nesta classe, neste campo, assim que ela for construída. Com isso, basta utilizar o mesmo no interior da ação/controller.

[Export]
public class TesteController : ApiController
{
    [Import]
    private IRequestTracking tracking;

    [HttpGet]
    [RequestTrackingFilter]
    public string Ping(string valor)
    {
        tracking.AddStep(string.Format(“TesteController.Ping({0})”, valor));

        return valor + ” ping”;
    }
}

É importante notar que o atributo criado anteriormente é decorado no méotdo Ping, e é a presença dele que faz com o que o runtime do ASP.NET o execute.

Além destas opções, podemos também acessar e utilizar este rastreador, por exemplo, dentro de um message handler. Além de utilizar para também adicionar mais um passo ao rastreador, é também o momento de invocar o método Flush para que o conteúdo armazenado até o momento seja definitivamente adicionado no arquivo de trace, previamente configurado. Como podemos notar no código abaixo, fazemos todo este trabalho depois que a requisição foi processada por todos os componentes (de mais baixo nível), incluindo a ação que está dentro do controller. O flush é feito momentos antes de retornar a resposta para o cliente.

public class FlushingRequestTrackingHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        return await base.SendAsync(request, cancellationToken).ContinueWith(r =>
        {
            var tracking =
                ((IRequestTracking)request
                    .GetDependencyScope()
                    .GetService(typeof(IRequestTracking)));

            tracking.AddStep(“FRTH.SendAsync”);
            tracking.Flush();

            return r.Result;
        });
    }
}

E, ao rodar e visualizarmos o arquivo de tracing, teremos:

13/11/2014 15:44:34 – Id: 724b2a97-3bcf-428b-a65e-5ec582bb1f70 – OnActionExecuting
13/11/2014 15:44:34 – Id: 724b2a97-3bcf-428b-a65e-5ec582bb1f70 – TesteController.Ping(teste)
13/11/2014 15:44:34 – Id: 724b2a97-3bcf-428b-a65e-5ec582bb1f70 – OnActionExecuted
13/11/2014 15:44:34 – Id: 724b2a97-3bcf-428b-a65e-5ec582bb1f70 – FRTH.SendAsync

Importante: Apesar de tentador, é necessário tomar cuidado ao acessar o gestor de dependências através da propriedade fornecida pela GlobalConfiguration.Configuration.DependencyResolver. O problema é que esta propriedade sempre retornará uma nova instância do gestor (no nosso caso, do MefResolver) e não teremos os objetos sendo mantidos por toda a requisição.

Cancelando Requisições do HttpClient

Como sabemos, a classe HttpClient é uma espécie de proxy para o consumo de serviços REST a partir de aplicações .NET. Durante a sua criação é possível realizar diversas configurações, e as requisições que saem e chegam, compartilham estas configurações, evitando que se faça isso a cada nova requisição/resposta que é enviada/processada.

Entre os diversos métodos que esta classe fornece, o mais completo, ou melhor, “de mais baixo nível”, é o SendAsync, que onde podemos (e devemos) configurar completamente a mensagem, especificando desde a URL até o método HTTP que será utilizado. Como facilitador, existem alguns métodos que foram criados sobre o método SendAsync, e foram nomeados utilizandos os verbos do HTTP (GET (GetAsync), POST (PostAsync), etc.).

A classe HttpClient fornece um método chamado CancelPendingRequests, que como o próprio nome sugere, solicitará o cancelamento de todas as requisições que estão sendo realizadas pela respectiva instância do HttpClient. Mas é provável que queremos ter um controle individual das requisições e conseguirmos cancelar especificamente uma delas.

Felizmente todos os métodos que iniciam uma nova requisição possuem um parâmetro onde é permitido controlar e, principalmente, cancelar a execução da mesma. Eles fazem uso de uma classe chamada CancellationTokenSource, que faz parte do .NET Framework, e possibilita ao chamador informar ao runtime que deseja cancelar a requisição que está em andamento.

Para exemplificar o seu uso, vamos utilizar uma aplicação WPF para iniciará a requisição, e enquanto ela estiver sendo executada, vamos dar a possibilidade ao usuário dele conseguir cancelar a mesma. Note no código abaixo que criamos em nível da classe um membro chamado status, qual será o responsável por gerenciar um eventual cancelamento. No clique do botão Requisitar, estamos recorrendo ao método GetAsync (chamando-o de forma assíncrona) e passamos o CancellationTokenSource. É importante notar que temos que envolver este código em um bloco try/catch para interceptar a exceção do tipo TaskCanceledException, que será disparada quando o cancelamento for efetivamente realizado.

public partial class MainWindow : Window
{
private CancellationTokenSource status;
private HttpClient proxy = new HttpClient();

    private async void Requisitar_Click(object sender, RoutedEventArgs e)
{
Reinicializar();

        try
{
var resposta = await proxy.GetAsync(Url.Text, status.Token);

            if (resposta.IsSuccessStatusCode)
Conteudo.Text = await resposta.Content.ReadAsStringAsync();
}
catch (TaskCanceledException)
{
Conteudo.Foreground = Brushes.Red;
Conteudo.Text = “*** A REQUISIÇÃO FOI CANCELADA ***”;
}
}

    private void Reinicializar()
{
Conteudo.Text = null;
Conteudo.Foreground = Brushes.Black;

        status = new CancellationTokenSource();
}

    private void Cancelar_Click(object sender, RoutedEventArgs e)
{
status.Cancel();
}
}

Agora o cancelamento pode ser solicitado ao clicar no botão Cancelar, e através do método Cancel da classe CancellationTokenSource, o código para o qual passamos este token (que foi o GetAsync) identifica a solicitação e cancela a execução, disparando a exceção que falamos acima. As imagens abaixo ilustram tanto a requisição sendo executada com sucesso quanto um cancelamento sendo solicitado e acatado, abortando o processamento.