Israel Aece

Software Developer

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.



Análise de Headers antes da carga do Conteúdo

Quando fazemos a requisição através da classe HttpClient, informamos o endereço do recurso que queremos acessar, e através de algum método, como por exemplo, o GetAsync, é possível receber o resultado esperado. Apesar de na maioria das vezes já sabermos o que o teremos como resultado, em alguns momentos podemos querer fazer alguma verificação antes de materializar o conteúdo que foi retornado.

A questão é que para materializar o tal conteúdo, precisamos alocar memória e realizar algum processamento, e que pode ser desnecessário dependendo da uma eventual condição que temos que avaliar antes de efetivamente carregar o conteúdo. Para os métodos expostos pela classe HttpClient, há uma versão que nos permite passar uma das opções do enumerador HttpCompletionOption, a saber.

  • ResponseHeadersRead: indica que a operação deve ser considerada como completa depois que os headers forem lidos. A conteúdo ainda não.
  • ResponseContentRead: indica que a operação somente será considerada como completa depois que todo o corpo da mesma já tenha sido lido e materializado.

Como vamos buscar o conteúdo através do método GetAsync, iremos definir a opção ResponseHeadersRead para analisarmos os headers antes de carregar o conteúdo. Quando a requisição voltar, faremos a verificação para analisar se o conteúdo (através do header Content-Type) é ou não do tipo HTML, e se for, o acessamos da forma que desejarmos. Essa técnica evitará o carregamento desnecessário do corpo da mensagem, ou seja, postergaremos a carga até que se realmente precise dela, poupando recursos da máquina de onde o consuma está sendo realizado.

using (var client = new HttpClient())
{
    var resposta =
        await client.GetAsync("http://www.microsoft.com", HttpCompletionOption.ResponseHeadersRead);

    if (resposta.Content.Headers.ContentType.MediaType != "text/html")
    {
        var conteudo = await resposta.Content.ReadAsStringAsync();

        //utilizar o conteúdo
    }
}

Recebendo Notificações com SSE

É muito comum aplicações Web precisarem receber informações do servidor para que seja possível atualizar a página em que o usuário se encontra, ou até mesmo para receber notificações de que algo ocorreu e que isso possa interessar ao mesmo. Existem diversas técnicas que possibilitam esse objetivo, e uma das mais conhecidas é o polling, que consiste em criar um timer no cliente (HTML/JavaScript) que periodicamente verifica no servidor se há alguma atualização.

O problema desta técnica é ter que ficar gastando tempo e recurso, e dependendo da forma como as informações são disponibilizadas, podemos demandar todo este recurso para que não se receber nada. Um novo recurso, disponível a partir do HTML 5, é o Web Sockets, possui uma vasta gama de recursos, incluindo a comunicação bidirectional entre o cliente e o servidor, e pode atender completamente esta demanda. Só que em algumas vezes precisamos apenas do recebimento de informações do servidor, e o Web Sockets para soar como um excesso para essa atividade.

O HTML 5 ainda fornece um recurso chamado de Server Sent Events (SSE), e com uma API de fácil utilização, é possível estabelecer a comunicação e receber as notificações do servidor. O ASP.NET Web API também fornece uma forma de estabelecer, via stream, uma ligação com o cliente, e qualquer coisa que se escreva neste stream, o mesmo receberá e irá tratar a mesma como quiser. A finalidade deste artigo é explorar a utilização do SSE para notificar os usuários sobre novas notícias que acontecerão.



Vamos iniciar pelo lado do servidor. Iremos criar um controller no ASP.NET Web API para gerenciar os assinantes, receber as notícias e publicá-las. Podemos reparar na classe abaixo que há uma coleção chamada assinantes que armazenará os streams dos clientes conectados. O método Assinar é responsável por receber a requisição dos clientes interessados, e no construtor da classe PushStreamContent definimos um delegate que irá instanciar o StreamWriter e armazenará na coleção.

public class NoticiasController : ApiController
{
    private static ConcurrentBag<StreamWriter> assinantes = new ConcurrentBag<StreamWriter>();

    [HttpGet]
    public HttpResponseMessage Assinar(HttpRequestMessage requisicao)
    {
        return new HttpResponseMessage()
        {
            Content =
                new PushStreamContent(
                    (stream, content, context) =>
                        assinantes.Add(new StreamWriter(stream) { AutoFlush = true }),
                    "text/event-stream")
        };
    }
}

Nós já utilizamos a classe PushStreamContent no artigo que vimos como exibir vídeos pelo ASP.NET Web API, e da mesma forma aqui, o StreamWriter que ela armazenará servirá para que as strings sendo escritas nele viajem até os respectivos clientes. Por fim, o media-type text/event-stream que quando informado no Content-Type da resposta, permite aos clientes entender que esta resposta seja entendida como um canal que receberá constantes informações.

Uma vez que temos os assinantes, chega o momento da geração do conteúdo e, principalmente, a entrega das informações para os clientes. O primeiro método que vemos abaixo, AdicionarNoticia, recebe uma nova notícia, armazena em algum repositório e notificamos os clientes que estão adicionados na coleção.

[HttpPost]
public async Task AdicionarNoticia(Noticia noticia)
{
    //Armazenar em algum repositório

    await Notificar(noticia);
}

private async static Task Notificar(Noticia noticia)
{
    foreach (var assinante in assinantes.ToList())
    {
        try
        {
            await assinante.WriteAsync(
                string.Format("data: {0}\n\n", JsonConvert.SerializeObject(noticia)));
        }
        catch
        {
            StreamWriter sw = null;
            assinantes.TryTake(out sw);
        }
    }
}

O método Notificar percorre a coleção e via o método WriteAsync do Stream publicamos a nova notícia aos clientes. Como sabemos, o StreamWriter nos permite mandar strings, e através de um serializador (neste caso em formato JSON) temos a oportunidade de mandarmos objetos complexos, e como o JavaScript lida de forma fácil com este formato, não teremos muitos problemas em exibir essa informação. A única preocupação que temos que ter é com relação a como mandamos a string para o cliente, ou seja, prefixando com o "data: MensagemAqui\n\n".

Agora que já temos tudo o que é necessário do lado do servidor, chega o momento em que temos que codificar o cliente, e assim utilizando efetivamente o SSE. Infelizmente o Internet Explorer não dá suporte à este recurso, e para o exemplo, vamos utilizar o Chrome. A primeira condicional é para avaliar se o navegador dá suporte para o SSE. Caso seja suportado, então instanciamos a classe EventSource e informamos o endereço para o método Assinar. Uma vez que a ligação estiver estabelecidade, as mensagens começarão a chegar, e vamos capturar essas mensagens através do evento onMessage, fazemos o parse da string transformando-a em JSON e, consequentemente, acessar as propriedades.

<script>
    if (!!window.EventSource) {
        var sse = new EventSource("/api/Noticias/Assinar");

        sse.onmessage = function (e) {
            $('#NovaNoticia').text($.parseJSON(e.data).Titulo);
            $('#AlertaDeNoticia').modal();
        };
    }
</script>

Finalmente, quando o navegador estiver aberto em uma página HTML com o código acima, e uma nova notícia for postada, uma pop-up é aberta exibindo a mesma, assim como é mostrado na imagem acima.

OwinHost.exe

A arquitetura do OWIN está tornando o ambiente de execução de aplicações Web (ASP.NET) muito mais simples e de fácil estensibilidade, sem contar no alívio de performance que ele traz para estes tipos de aplicações, pois está aos poucos tentando diminuir a dependência do assembly System.Web.dll.

Uma das características da arquitetura OWIN é a independência do host onde a aplicação roda. Hoje, quando criamos um projeto no Visual Studio, por padrão, ao pressionar F5, o IIS Express inicia para executar a aplicação para que possam realizar os testes e, principalmente, depurar quando for necessário. O Microsoft OWIN já fornece a implementação de host para rodar a aplicação sobre o pipeline do ASP.NET e uma implementação para self-hosting.

Mas como ele foi criado com a estensibilidade sendo um de seus pilares, a sua API é estensível o suficiente para que se crie novos tipos de hosts. E foi isso que a Microsoft fez para testes de aplicações que são "puramente" OWIN, ou seja, criou uma nova opção para rodar aplicações OWIN no Visual Studio (ou fora dele) que é o OwinHost.exe, e vamos ver sua utilização no decorer deste artigo.

Mesmo utilizando a template Empty do ASP.NET Web Application, o projeto já nasce com a System.Web.dll referenciada e uma porção de outros assemblies que também estão relacionados a ela. Se simplesmente rodarmos a aplicação, o IIS Express entra em ação para hospedar e gerenciar a execução da mesma.

Para os testes, exclui todos estes assemblies e referenciei dois pacotes (via Nuget): Owin e Microsoft.Owin. Depois disso, criei o código abaixo que recebe a requisição e retorna uma simples resposta. Se tentar rodar esta aplicação com esta configuração, não será possível executa-la pois o IIS Express não saberá como lidar com esse tipo de código.

[assembly: OwinStartup(typeof(WebApplication1.Startup))]

namespace WebApplication1
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.Run(ctx => ctx.Response.WriteAsync("Bem-vindo!"));
        }
    }
}

Se fizermos questão de utilizar o IIS Express (ou IIS), então será necessário a adição de mais um pacote, que é o Microsft.Owin.Host.SystemWeb, que como falei acima, faz com que o OWIN rode sobre o pipeline do ASP.NET. Mas isso não é o que queremos fazer. Ao invés de utilizarmos o IIS, vamos recorrer ao OwinHost, e é este também o nome do pacote disponível via Nuget.

Quando adicionamos este pacote ao projeto, passa a aparecer um novo tipo de host disponível nas configurações do projeto, assim como é mostrado na imagem abaixo. Quando o OwinHost é escolhido entre as opções, algumas configurações específicas são apresentadas, que basicamente determinam a URL e porta onde a aplicação rodará.



Ao rodar a aplicação, o OwinHost.exe se inicia (via console) e o navegador é aberto para que seja possível navegar pela aplicação. E, como podemos notar, isso abrirá as portas para que novos tipos de hosts sejam criados, e independente de qual escolhermos, o Visual Studio evolui para tentar continuar dando a mesma experiência (leia-se facilidade) quando desenvolvemos com ele.

Validade do Cookie no CookieAuthenticationMiddleware

Falei em um outro artigo sobre um componente que temos no OWIN que substitui o Forms Authentication (que é o CookieAuthenticationMiddleware). Como vimos naquele artigo, uma vez que o usuário se identificou como válido para aplicação, este componente é o responsável por emitir o cookie e embutir na resposta; em futuras requisições, o navegador será responsável por encaminhar este cookie, e este mesmo componente fará a validação para saber se o mesmo ainda continua válido.

Por válido me refiro aqui a duas verificações: integridade, que é a garantia que o mesmo não foi alterado entre a ida e a volta e o tempo de expiração. Ambos podem ser configurados através da classe CookieAuthenticationOptions. Só que podemos ter outras coisas que deveriam invalidar o acesso do usuário, como por exemplo, mudanças em seu perfil e/ou a remoção de uma permissão que ele possui(a), e as vezes, por questões de segurança, não podemos esperar até que o cookie expire para renovar as credenciais do usuário.

Apesar deste componente não fazer isso nativamente, ele possui um ponto de estensibilidade que nos permite acoplar um código customizado e fazer esta validação (de forma centralizada). A classe  CookieAuthenticationOptions expõe uma propriedade chamada Provider, que recebe a instância de uma classe do tipo CookieAuthenticationProvider, que por sua vez, possui várias propriedades, que via delegates, conseguimos interceptar e customizar diversos pontos da execução deste componente.

Entre eles, temos a propriedade OnValidateIdentity, que como o nome sugere, nos permite avaliar se a identidade é, ou melhor, continua válida. No exemplo abaixo estamos recorrendo ao gestor de usuários (repositório) e verificando se o mesmo continua sendo válido. Caso não seja, invocamos o método RejectIdentity (que está disponível através do contexto da execução) e obriga o usuário novamente a se identificar para a aplicação, redirecionando-o para a tela de login.

public void Configuration(IAppBuilder app)
{
    app.UseCookieAuthentication(new CookieAuthenticationOptions()
    {
        AuthenticationType = "AppTeste",
        LoginPath = new PathString("/Seguranca/Login"),
        Provider = new CookieAuthenticationProvider()
        {
            OnValidateIdentity = async ctx =>
            {
                if (!(await GestorDeUsuarios.ValidarCadastroDoUsuario(ctx.Identity.Name)))
                    ctx.RejectIdentity();
            }
        }
    });
}

Se quiser tornar a experiência mais amigável para o mesmo, ao invés de utilizar o método RejectIdentity podemos recorrer ao método ReplaceIdentity, gerando uma nova identidade já refletindo as mudanças que foram realizadas na base de dados. O método ValidarCadastroDoUsuario pode fazer a verificação de diversas formas, e entre delas, podemos recorrer à um eventual timestamp que a tabela de usuário possa ter, o que permitirá identificar de forma fácil se alguma informação (coluna) foi alterada..

Utilizando o HTTPS no ASP.NET Web API

Há algum tempo já é possível criar certificados para testarmos em nossas aplicações. Entre os tipos de aplicações que utilizamos certificados, temos aplicações Web (HTML ou APIs) que são expostas através de HTTP e HTTPS. Apesar dos certificados que são considerados "válidos" para o Mercado, devem ser comprados de uma autoridade certificadora (VeriSign, por exemplo), em tempo de desenvolvimento não necessitamos ter todo esse luxo.

Entre as várias opções que temos para criarmos certificados para testes, uma delas é recorrer ao próprio IIS, que possibita a criação de certificados autoassinados, e que podemos perfeitamente utilizar em um ambiente de desenvolvimento. A imagem abaixo ilustra a criação do mesmo e já podemos ver um site configurado com este certificado recém criado.



Se hospedarmos neste site uma Web API, poderemos acessá-la via HTTP ou via HTTPS, afinal, o site dá suporte para estes dois protocolos (bindings). Se quisermos, via programação, forçar com que a requisição seja, obrigatoriamente, realizada através do HTTPS, podemos avaliar antes de executar efetivamente a ação que estão sendo solicitada. Para dar mais flexibilidade, vamos criar um filtro que pode (e deve) ser aplicado naquelas ações que queremos que a mesma esteja sendo acessada através de HTTPS.

public class ValidacaoDeHttps : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        var request = actionContext.Request;

        if (request.RequestUri.Scheme != Uri.UriSchemeHttps)
        {
            actionContext.Response =
                request.CreateResponse(
                    HttpStatusCode.Forbidden,
                    new StringContent("É necessário que a requisição seja HTTPS."));
        }
    }
}

Com esta classe criada, podemos decorar as ações que devem ser protegidas pelo transporte. O código abaixo ilustra a utilização deste atributo:

[ValidacaoDeHttps]
public string Get()
{
    return "XPTO";
}

IMPORTANTE: Ao acessar o serviço no navegador, podemos receber um aviso dizendo que o certificado não é confiável. Quando acessamos um recurso via HTTPS, uma das validações que é realizada é identificar se o nome domínio do certificado corresponde ao domínio da URL que estamos acessando. No meu caso, minha máquina chama IsraelAeceNB1; se acessar o serviço como localhost, então um aviso indicando a inconsistência será apresentado. Se utilizar o nome da máquina, então esse aviso não será exibido.

Vale lembrar que esse problema não ocorre somente no navegador. Se estivermos acessando o recurso através do HttpClient, uma exceção será disparada para indicar esse problema. Existe um recurso presente no .NET Framework, que é a possibilidade de interceptar essa validação e, consequentemente, tomar a decisão se podemos ou não aceitar o certificado, mesmo com esta falha. Essa validação deve ser configurada através do delegate ServerCertificateValidationCallback, assim como foi já comentado neste outro artigo.

No exemplo abaixo, estamos acessando o serviço via HTTPS com a URL definida como localhost (o que é suficiente para apresentar o erro), e como estamos dando um by-pass, a requisição é realizada com sucesso. Apesar disso ser útil em um ambiente de testes, é importante dizer que raramente deverá utilizar isso em produção, pois devemos sempre utilizar um "certificado válido".

ServicePointManager.ServerCertificateValidationCallback =
    (sender, certificate, chain, sslPolicyErrors) => true;

using (var client = new HttpClient())
{
    var r = client.GetAsync("https://localhost/api/Informacoes").Result;

    Console.WriteLine(r.StatusCode);
    Console.WriteLine(r.Content.ReadAsStringAsync().Result);
}

Lidando com cookies no WCF

Há algum tempo falei aqui sobre a propriedade AllowCookies dos bindings HTTP e seu funcionamento. Apesar do WCF suportar cookies, era um pouco complicado lidar (gerar e extrair) com eles, ou seja, havia muito código (e não muito intuitivo) a ser escrito para atingir este objetivo.

Como isso é algo comum quando trabalhamos com o protocolo HTTP, então a Microsoft facilitou o acesso aos cookies a partir da versão 4.5 do .NET/WCF. A partir de agora, é possível o cliente lidar diretamente com a classe a CookieContainer, que representa a coleção de cookies e possui um acesso aos mesmos de forma mais simples.

Para acessarmos este novo recurso, podemos recorrer a factory que utilizamos para construir o proxy no cliente, e através da interface IHttpCookieContainerManager chegamos até o CookieContainer. A partir daí, a inclusão e leitura de cookies (gerados pelo servidor) é extremamente simples, assim como podemos visualizar através do código abaixo:

var url = "http://localhost:8272/srv";

using
(var host = new ServiceHost(typeof(Servico)))
{
    host.AddServiceEndpoint(typeof(IContrato), new BasicHttpBinding() { AllowCookies = true }, url);
    host.Open();

    using (var factory =
        new ChannelFactory<IContrato>(
            new BasicHttpBinding() { AllowCookies = true },
            url))
    {
        var proxy = factory.CreateChannel();
        var container = factory.GetProperty<IHttpCookieContainerManager>().CookieContainer;

        //Gerando um Cookie
        container.Add(new Uri(url), new Cookie("Info", "Cliente->Servidor"));

        Console.WriteLine(proxy.Ping("Israel Aece"));

        //Extraindo um Cookie
        Console.WriteLine(container.GetCookies(new Uri(url))[0]);
    }
}