Substituindo o Framework de AOP

by Israel Aece 7. May 2012 23:28

Quando desenvolvemos um software, ou uma parte dele, além da parte relacionada ao negócio em si, nas maioria das vezes, precisamos recorrer a códigos de infraestrutura, que são responsáveis por gerenciar alguns recursos que estão indiretamente relacionados ao processo.

Geralmente mencionamos o termo cross-cutting concerns, que se referem a funcionalidades que podem se estender e afetar várias partes do sistema. Autenticação, Autorização, Logging e Transação, são algumas das funcionalidades que poderiam ser candidatas a serem encaradas e implementadas desta forma.

Apesar de possível, não é interessante misturar este tipo de funcionalidade com o código de negócio, pois facilmente você poderá agregar mais funcionalidade do que deveria. Além disso, a modularização é extremamente importante, pois facilita a manutenção, e eventuais alterações mais complexas. Como estas funcionalidades interceptam várias partes do sistema e em diversos níveis, uma das formas mais comuns de se acoplar isso à execução, é através da técnica de AOP, Aspect Oriented Programming.

Em .NET, existe um framework chamado PostSharp. Este é um framework fornece alguns atributos para decorar em elementos do nosso código, e onde o aplicamos, ele utilizará IL Weaving durante a compilação, reescrevendo o código para adicionar os comportamentos necessários, e durante a execução, serão executados de forma automática (e mágica?), sem que o nossos códigos de negócios mencionem diretamente funcionalidades de cross-cutting.

Apesar do framework fazer um grande trabalho, reescrevendo a IL para injetar o código customizado em torno do local onde o aplicamos, poderíamos trabalhar de forma semelhante, sem qualquer mágica envolvida. Tudo isso, utilizando apenas classes customizadas, onde você poderá ter o controle total, e tudo isso, sem a necessidade de envolver algum framework de terceiro.

Para exemplificar, podemos criar uma classe que representa um comando a ser executado. Basicamente, cada comando carrega as informações necessárias para que o mesmo possa ser executado, como por exemplo: criar, configurar e por fim, gravar um novo cliente na base de dados. Mas o comando por si só não funcionará. Isso quer dizer que vamos precisar de um tratador, ou seja, aquele que irá recepcionar o comando (que contém os dados), executando-o para que o cliente seja efetivamente gravado na base de dados.

Neste comando, poderíamos envolvê-lo em um bloco transacionado, efetuar o logging de algumas informações, mensurar o tempo de execução, etc. Mas como dito acima, colocar códigos de cross-cutting aqui, faria com que tivessemos algumas outras preocupações, e isso, voltaria a acontecer em todos os comandos que nossa aplicação venha a ter. Redundância e descentralização seriam alguns dos problemas que poderíamos enfrentar, sem contar a eventual necessidade de ter que injetar dependências indiretas ao comando (aquelas exigidas pela infraestrutura).

Abaixo temos o diagrama de classes que resume todos os tipos utilizados na solução. Classes sufixidas com a palavra "Handler", correspondem aos tratadores dos comandos, e como eles estão implementados no formato de russian-dolls, podemos adicionar um dentro do outro, fazendo com que eles sejam executados antes ou depois do outro comando que você adicionou.

Repare que no código abaixo, LogingHandler, ele herda da classe abstrata CommandHandler, recebendo em seu construtor a instância de um próximo comando, qual será executado "entre este comando".

public class LoggingHandler : CommandHandler
{
    private readonly CommandHandler next;

    public LoggingHandler(CommandHandler next)
    {
        this.next = next;
    }

    protected override void ExecuteInternal(Command command)
    {
        Console.WriteLine("* Início da Execução do Comando.");
        this.next.ExecuteCommand(command);
        Console.WriteLine("* Fim da Execução do Comando.");
    }
}

Se evoluirmos um pouco mais o código, podemos criar métodos de extensão, para que cada um deles seja responsável por retornar um novo tratador, envolvendo nele o tratador atual, aquele onde está sendo aplicado a estensão. Neste caso, podemos nomear os métodos, de acordo com a funcionalidade que cada um deles agrega à execução:

public static class Estensoes
{
    public static CommandHandler ComTransacao(this CommandHandler handler)
    {
        return new TransactionHandler(handler);
    }

    public static CommandHandler MedindoTempo(this CommandHandler handler)
    {
        return new TimerHandler(handler);
    }

    public static CommandHandler GerandoLog(this CommandHandler handler)
    {
        return new LoggingHandler(handler);
    }
}

Como os métodos de estensão criados acima estão sendo aplicados ao tipo CommandHandler, podemos agregar ao mesmo qualquer uma das funcionalidades, de uma "forma fluente". Com todos os tratadores do diagrama acima implementados, podemos escrever um código parecido com esse:

new CadastrarClienteHandler()
    .ComTransacao()
    .GerandoLog()
    .MedindoTempo()
    .ExecuteCommand(new CadastrarCliente() { Nome = "Israel" });

E, finalmente, o resultado depois da execução:

  • Início da Execução do Comando 'CadastrarCliente'.
  • Início do Bloco Transacionado.
  • Cadastrando o Cliente 'Israel'.
  • Commit da Transação.
  • Fim do Bloco Transacionado.
  • Fim da Execução do Comando 'CadastrarCliente'.
  • Tempo Decorrido: 00:00:00.0042806.

Tags: , ,

C#

Configuração dinâmica no WCF

by Israel Aece 24. April 2012 23:35

Existem duas formas de configurar um serviço WCF: imperativa e declarativa. A primeira opção consiste em criar explicitamente a classe ServiceHost, configurá-la e gerenciar a sua execução, e tudo isso é feito diretamente através da linguagem (C# e VB.NET). Já no modelo declarativo, recorremos ao arquivo de configuração (App.config ou Web.config), onde tudo é configurado dentro deles, o que te dá uma maior flexibilidade, já que te permite alterar mesmo depois de instalado no servidor.

Quando queremos algum dinamismo na configuração do serviço, podemos recorrer a primeira opção. Mas quando estamos hospedando o serviço em um projeto Web, através de um arquivo *.svc, a construção da classe ServiceHost é criada automaticamente pelo WCF/ASP.NET.

Nestes casos, para conseguir atingir o nosso objetivo, devemos construir uma factory customizada, e para isso, precisamos criar uma classe herdando de ServiceHostFactory, sobrescrever o método CreateServiceHost, onde dentro dele, criaremos o ServiceHost de acordo com nossa necessidade e, finalmente, acoplamos  à execução através da diretiva @ServiceHost no arquivo *.svc. Mais detalhes aqui.

Na versão 4.5 do WCF, a Microsoft facilitou isso, sem a necessidade de fazer várias customizações e configurações. Basicamente colocamos na classe que representa o serviço, um método estático chamado Configure, que receberá como parâmetro a instância da classe ServiceConfiguration, e como o próprio nome diz, corresponde as configurações daquele serviço, e que será aplicado ao ServiceHost. O código abaixo ilustra este novo recurso. Isso irá eliminar tudo aquilo que fazíamos até então, para conseguir customizar e/ou gerar a configuração para os serviços que são hospedados no IIS.

public class Servico : IContrato
{
    public static void Configure(ServiceConfiguration config)
    {
        config.Description.Behaviors.Add(
            new ServiceMetadataBehavior() { HttpGetEnabled = true });

        config.Description.Behaviors.Add(
            new ServiceDebugBehavior() { IncludeExceptionDetailInFaults = true });
    }

    public string Ping(string value)
    {
        return value + " ping";
    }
}

Tags:

WCF

Compressão no .NET Framework 4.5

by Israel Aece 24. April 2012 00:28

Há algum tempo, eu falava aqui sobre compressão de arquivos no .NET Framework. Temos à disposição as classes GZipStream e DeflateStream para manipular arquivos, ou melhor, conteúdos que necessitam ser compactados ou descompactados utilizando estes dois algoritmos (Deflate e GZip).

Apesar de funcionar em alguns cenários, é um pouco difícil trabalhar em situações mais comuns quando precisamos lidar com (des)compactação. Um exemplo típico é quando precisamos compactar um diretório todo, ou múltiplos arquivos em um único arquivo *.zip. Além disso, toda a manipulação precisa ser realizada através do uso de streams, ou seja, temos que lidar com a alocação e cópia dos bytes entre a origem e o destino.

Como as operações comuns são as mais complicadas de serem utilizadas, recorremos à frameworks externos, como é o caso do SharpZipLib, que fornece várias funcionalidades interessantes acerca da utilização de ZIPs. Finalmente, a partir da versão 4.5 do .NET Framework, a Microsoft incluiu novas classes que visa facilitar a manipulação destes tipos de arquivos em aplicações .NET.

Apesar dos novos tipos estarem debaixo do namespace System.IO.Compression, eles são fornecidos através da referência de novos assemblies que fazemos em nossas aplicações: System.IO.Compression.dll e System.IO.Compression.FileSystem.dll. O primeiro assembly fornece os tipos de mais baixo nível para trabalhar com ZIP; já as classes disponíveis dentro do segundo assembly, temos apenas alguns utilitários (classes estáticas) que tornam ainda mais fácil a geração e consumo de ZIPs pela aplicação.

A primeira classe que vamos falar é a ZipArchive, que corresponde a um pacote de arquivos comprimidos, que pode ser um ou N arquivos. Para cada conteúdo (arquivo) dentro do ZipArchive, existe uma classe que o descreve: ZipArchiveEntry. E como já era de se esperar, a classe ZipArchive fornece uma propriedade chamada Entries, que retorna a coleção de entradas, e podemos notar isso na imagem abaixo:

A classe ZipArchiveEntry não é criada diretamente, ou seja, através de um construtor público. A primeira opção para a sua criação, é através do método CreateEntry da classe ZipArchive, que recebe como parâmetro o nome da entrada, e que muitas vezes, se você estiver compactando um arquivo, o nome da entrada pode refletir o nome do arquivo que está sendo inserido.

No exemplo abaixo, abrimos a conexão com um arquivo de destino via FileStream. Esse arquivo será o arquivo compactado, ou seja, as entradas criadas serão colocadas nele. O stream que aponta para o arquivo Dados.zip, é passado no construtor da classe ZipArchive, e logo em seguida, percorremos os arquivos do diretório C:\Temp, onde para cada arquivo, criamos uma entrada dentro do ZipArchive. Por fim, copiamos o conteúdo do arquivo da origem para o destino, ainda operando com streams. O código abaixo ilustra este trabalho:

using (var output = new FileStream("Dados.zip", FileMode.Create))
using (var archive = new ZipArchive(output, ZipArchiveMode.Create))
    foreach (var filename in Directory.GetFiles(@"C:\Temp\"))
        using (var source = File.Open(filename, FileMode.Open))
        using (var destination = archive.CreateEntry(Path.GetFileName(filename)).Open())
            source.CopyTo(destination);

Ao rodar esse código, efetuamos a compactação de todos os arquivos que estão no diretório C:\Temp. Para os testes, existem dois arquivos neste diretório, totalizando cerca de 11 MB. E depois de serem compactados, e colocados no arquivo Dados.zip, o valor cai para 316 KB, assim como podemos perceber através da imagem abaixo:

Como comentei acima, com o intuito de facilitar ainda mais a criação de conteúdo compactado, vamos reescrever este código utilizando um novo método de estensão, chamado CreateEntryFromFile, que dado o arquivo de origem e o nome da entrada, ele automaticamente cria a mesma, já copiando todo o conteúdo para dentro dela. Vemos que o código fica mais simples ao utilizar essa opção:

using (var output = new FileStream("Dados.zip", FileMode.Create))
using (var archive = new ZipArchive(output, ZipArchiveMode.Create))
    foreach (var filename in Directory.GetFiles(@"C:\Temp\"))
        archive.CreateEntryFromFile(
            filename,
            Path.GetFileName(filename),
            CompressionLevel.Optimal);

E para facilitar ainda mais, temos um método estático disponível através da classe ZipFile, chamado CreateFromDirectory, que dado o endereço do diretório e o caminho para o arquivo de destino, ele já cria as entradas para cada arquivo, copia o conteúdo e, finalmente, gera o arquivo compactado. Por fim, em uma única linha, conseguimos reescrever os mesmos códigos que vimos acima:

ZipFile.CreateFromDirectory(@"C:\Temp", @"C:\Dados.zip");

Este método ainda fornece um overload, que além de permitir informar o nível da compactação, recebe um boleano, indicando se a pasta que está sendo compactada, deve ou não ser incluída como raiz do arquivo compactado. Abaixo, as imagens mostram quando utilizamos true, e logo na sequência, false, para este parâmetro:

ZipFile.CreateFromDirectory(
            @"C:\Temp",
            @"C:\Dados.zip",
            CompressionLevel.Optimal,
            true);

A extração do arquivo compactado para os arquivos isolados, são trabalhados de forma semelhante. E da mesma forma que na compactação, a descompactação também fornece alguns métodos utilitários que podem ser utilizados para realizar a extração dos arquivos que estão dentro do arquivo *.zip. Para exemplificar, no código abaixo, fazemos o uso do método estático ExtractToDirectory, exposto pela classe ZipFile. Este método recebe como fonte, o arquivo compactado, e o segundo parâmetro, corresponde ao caminho onde queremos extrair todo o conteúdo:

ZipFile.ExtractToDirectory(@"C:\Dados.zip", @"C:\Output\");

Tags:

.NET Framework

Utilizando o DataReader Assincronamente

by Israel Aece 22. April 2012 21:58

Na versão 2.0 do .NET Framework, a Microsoft incluiu uma série de novas funcionalidades em sua API de acesso a dados, o ADO.NET. Entre elas, podemos destacar o código genérico, MARS, Bulk-Copy e execução assíncrona de comandos e consultas.

O que tínhamos disponível naquela época é a implementação através do modelo assíncrono do .NET, que era implementado utilizando um par de métodos BeginXXX/EndXXX. Sendo assim, o método ExecuteReader passou a ter os métodos BeginExecuteReader e EndExecuteReader, enquanto o método ExecuteNonQuery, ganhou os métodos BeginExecuteNonQuery e EndExecuteNonQuery.

Da mesma forma, para ficar alinhado a nova forma de se trabalhar assincronamente nas linguagens, a execução assíncrona de comandos e consultas no ADO.NET 4.5 sofreu algumas mudanças, para seguir o modelo baseado em Tasks. Além das mudanças em nível das interfaces das classes, um detalhe importante é que não é mais necessário definir o flag Asynchronous Processing para True no arquivo de configuração, algo que sempre era descoberto somente depois que a aplicação estava em execução.

Para iniciar, a classe que representa a conexão (SqlConnection/DbConnection) fornecem a versão assíncrona do método Open, que é o OpenAsync. Este método retorna uma Task, o que a torna "aguardável", e com isso, podemos utilizar a keyword await para que a abertura possa ser realizada de forma assíncrona. Abaixo o código ilustra o uso deste método:

private async static Task Executar()
{
    using (var conn = new SqlConnection("..."))
    {
        await conn.OpenAsync();

        //...
    }
}

Como já era de se esperar, os mesmos métodos fornecidos na versão 2.0 do ADO.NET para processamento assíncrono, ganharam na versão baseada em Tasks na versão 4.5. No caso do ExecuteReader, temos o ExecuteReaderAsync. Já para o método ExecuteNonQuery, temos o ExecuteNonQueryAsync e, finalmente, para o ExecuteScalar, existe o ExecuteScalarAsync.

Todos estes métodos tratam-se da nova versão assíncrona, que basicamente retornam um objeto do tipo Task, que representa a tarefa que está sendo executada assincronamente. E, qualquer exceção que eventualmente ocorra dentro do processo assíncrono, ela será retornada/acessada através da Task que foi retornada pelo método. Abaixo temos um exemplo de como ler os dados através de DataReader, utilizando este novo modelo assíncrono:

private async static Task Executar()
{
    using (var conn = new SqlConnection("..."))
    {
        await conn.OpenAsync();

        using (var cmd = new SqlCommand("SELECT * FROM Cliente", conn))
            using (var dr = await cmd.ExecuteReaderAsync())
                while (await dr.ReadAsync())
                    if (!await dr.IsDBNullAsync(1))
                        Console.WriteLine(dr.GetString(1));
    }
}

Acima utilizamos o método ExecuteReaderAsync, mas ao percorrer o result-set retornado, utilizamos o - também novo - método ReaderAsync, que é a versão assíncrona, também baseada em Task,  do método Read do DataReader. Esse método em conjunto os métodos NextResultAsync, IsDBNullAsync e GetFieldValueAsync<T>, fornecem um controle muito mais refinado aos dados que estão sendo extraídos, pois quando olhamos um pouco mais de perto os internals de cada um deles, percebemos que a versão síncrona pode custar caro, prejudicando assim a escalabilidade.

Além disso, todos os métodos que vimos até aqui, possuem um segundo overload que suporta o cancelamento da tarefa custosa que está sendo executada. Para controlar o cancelamento, eles fazem uso da estrutura CancellationToken, e que podemos criar e informar ao invocar o método. Com uma pequena mudança na assinatura do método de exemplo que criamos acima (Executar), ele passará a receber o token que controla e propaga a notificação de cancelamento. Uma vez que o mesmo é repassado às tarefas que são executadas internamente, periodicamente o token é consultado para ver se o cancelamento foi ou não solicitado. A mudança é ligeira:

private async static Task Executar(CancellationToken ct)
{
    using (var conn = new SqlConnection("..."))
    {
        await conn.OpenAsync(ct);

        using (var cmd = new SqlCommand("SELECT * FROM Cliente", conn))
            using (var dr = await cmd.ExecuteReaderAsync(ct))
                while (await dr.ReadAsync(ct))
                    if (!await dr.IsDBNullAsync(1, ct))
                        Console.WriteLine(dr.GetString(1));
    }
}

Como percebemos, para preparar o método para permitir o cancelamento, é receber no parâmetro um CancellationToken, e propagá-lo para os métodos internos. Abaixo, estamos consumindo o método Executar que criamos, só que agora estamos passando um token que que será cancelado em dois segundos. Se depois deste tempo o método não concluir, uma exceção será disparada, informando que a tarefa foi cancelada.

var cts = new CancellationTokenSource();

try
{
    cts.CancelAfter(TimeSpan.FromSeconds(2));
    Executar(cts.Token).Wait();
}
catch (Exception ex)
{
    //trata exceção
}

Tags: , ,

Async | Data

Microsoft Fakes no Visual Studio 2011

by Israel Aece 18. April 2012 23:13

Ao escrever testes unitários antes do código que define as regras dos negócios, conseguimos identificar uma série de detalhes que nos ajuda a definir uma interface clara e consistente para nossos tipos, afinal, já estamos tendo uma visão do consumidor dos mesmos.

Além disso, essa técnica nos ajuda a identificar eventuais dependências que nossos tipos exigem e, consequentemente, isolá-las para que tenham certa flexibilidade, que com isso conseguiremos alternar facilmente entre uma implementação dummy e outra real. E mesmo durante a execução dos testes, é comum utilizarmos uma implementação fictícia, para que ela nos auxilie a testar uma regra específica, onde é irrelevante o uso de uma dependência real.

Outra questão que geralmente ocorre ao escrever testes, é o uso (dependência) de recursos estáticos ou de alguma outra coisa que é díficil simular, como uma classe que não permite sobrescrever seus membros. Um outro grande exemplo dessa dificuldade, é quando temos um código a ser testado que é sensível à data/hora. Como a propriedade Now da estrutura DateTime sempre retorna o horário atual, chamá-la duas vezes, sempre retornará valores diferentes, o que fica difícil definir se o teste sucedeu ou não.

Como parte de diversas melhorias que foram adicionadas na parte de testes do Visual Studo 2011, a Microsoft também incluiu novos recursos para resolver estes pequenos problemas que vimos acima. Microsoft Fakes é framework que ajuda na criação de implementações dummies em nossos testes, onde podemos facilmente simular certas situações injetando um código customizado.

Primeiramente vamos analisar um cenário em que essas novas funcionalidades podem ser interessantes. A classe abaixo, Log, define a estrutura de um item a ser logado. Recebemos em seu construtor a mensagem, e na sequência ele atribui a data atual à propriedade Data.

public class Log
{
    public Log(string mensagem)
    {
        this.Mensagem = mensagem;
        this.Data = DateTime.Now;
    }

    public string Mensagem { get; private set; }

    public DateTime Data { get; set; }
}

Ao escrever um teste que avalie se a data é mesmo atribuída, ele não vai passar. Note que como recorremos à propriedade Now, ela sempre retorna uma data diferente, e por mais que sejam poucos milisegundos, é o suficiente para ser diferente e, consequentemente, o teste falhará.

[TestMethod]
public void DeveAtribuirDataAtualAoLogCriado()
{
    Assert.AreEqual(DateTime.Now, new Log("Mensagem de Log").Data);
}

Eis que entra em cena os Shims. Esse tipo de fake nos permite fornecer uma implementação alternativa a membros estáticos ou tipos que não podem ser facilmente customizados (via herança, por exemplo). Para habilitá-o, temos que ir até o projeto de testes, onde o assembly com os tipos que estão sendo testados está referenciado, e clicar com o botão direito em cima daquele que queremos criar os fakes, e em seguida, na opção "Add Fakes Assembly", assim como vemos na imagem abaixo:

Isso pode ser feito em nossos próprios assemblies ou naqueles do .NET Framework, e independente de qual você escolha, um novo assembly será criado com a infraestrutura necessária para guiar e realizar essa simulação. Os shims são baseados em delegates, o que nos permitirá interceptar a chamada para qualquer método/propriedade, definindo uma "nova" implementação para eles, e que durante a execução, ela será executada, retornando assim, o resultado de acordo com a nossa necessidade. Abaixo a imagem ilustra os assemblies fakes que foram criados para os exemplos:

Logicamente que com esse procedimento, novos tipos foram criados. Como precisamos intervir no retorno da data atual, um novo tipo está disponível: ShimDateTime. A estrutura DateTime fornece a propriedade Now, e neste novo tipo, temos a propriedade NowGet (Get porque Now é somente leitura). Essa propriedade recebe a instância de um delegate do tipo Func<DateTime>, ou seja, deve apenas retornar um DateTime. Abaixo temos o código que exibe como configurá-la para retornar uma data específica.

[TestMethod]
public void DeveAtribuirDataAtualAoLogCriado()
{
    using (ShimsContext.Create())
    {
        ShimDateTime.NowGet = () => new DateTime(2012, 4, 18);

        Assert.AreEqual(DateTime.Now, new Log("Mensagem de Log").Data);
    }
}

Além dos tipos que foram criados durante o procedimento de criação dos fakes, existem alguns outros tipos que dão suporte à configuração e execução destes testes. O principal deles é ShimContext, que controla o tempo de vida dos shims. A forma mais fácil de criá-la é através do método estático Create, mas é extremamente importante envolve-lo em um bloco using, para delimitar claramente o bloco onde eles serão utilizados e, principalmente, encerrar o contexto quando os shims não forem mais necessários. Se não fizer isso, a propriedade NowGet retornará sempre 18 de abril de 2012.

Em uma outra situação, imaginemos uma classe que é responsável por avaliar certos índices, e quando eles ultrapassarem um certo valor, uma mensagem deve ser logada para posterior análise. O nosso monitor deverá depender de uma definição e não de uma implementação do repositório de logs, ou em outras palavras, a ideia é durante os testes, injetar um repositório que armazena os logs em memória, mas ao consumir isso por uma aplicação, utilizamos um repositório real, onde por exemplo, poderia gravar isso em um banco de dados. Abaixo temos a estrutura da interface IRepositorioDeLogs e da classe Monitor:

public interface IRepositorioDeLogs
{
    void Adicionar(Log log);

    IEnumerable<Log> Todos { get; }
}

public class Monitor
{
    private IRepositorioDeLogs repositorioDeLogs;

    public Monitor(IRepositorioDeLogs repositorioDeLogs)
    {
        this.repositorioDeLogs = repositorioDeLogs;
    }

    public void AvaliarIndice(double indice)
    {
        if (indice > 75)
            repositorioDeLogs.Adicionar(
                new Log(string.Format("O índice está acima dos 75.", indice)));
    }
}

Para efetuar o teste, precisamos passar uma classe que implemente a interface IRepositorioDeLogs, onde neste caso, adicionará os logs em uma lista na memória. Vale lembrar aqui, que os testes garantem que se o índice estiver acima, ele deve gravar o log, independente se está armazenado na memória ou não.

Ao invés de criar uma implementação dummy, podemos recorrer aos stubs, que também são fornecidos por este novo recurso do Visual Studio 2011. Stubs fornecem uma implementação padrão para cada um dos membros fornecidos, neste caso, pela interface IRepositorioDeLogs. Novamente, aqui também recorreremos ao uso de delegates para customizar a funcionalidade de cada membro.

Como criamos também os fakes para o assembly que contém nossos tipos, ele já criou a classe StubIRepositorioDeLogs. Essa classe fornece os campos AdicionarLog e TodosGet. O primeiro recebe um delegate do tipo Action<Log>, enquanto o segundo define um delegate do tipo Func<IEnumerable<Log>>. Com uma implementação simples, conseguiremos simular um repositório que conseguirá acomodar o log que será adicionado ao mesmo, mas isso se a regra da classe Monitor, alvo do teste, estiver em correta.

Para o exemplo, criamos uma coleção do tipo List<Log>, e no delegate do campo AdicionarLog, invocamos o método Add da coleção, enquando ao acessar a propriedade Todos, irá retorná-la na íntegra, e é justamente a propriedade Count que determinará o sucesso ou a falha do teste. O código abaixo ilustra esse procedimento utilizando o stub recém criado:

[TestMethod]
public void SeIndiceEstiverAcimaDe75DeveIncluirLog()
{
    var repositorio = new List<Log>();
    var stub = var StubIRepositorioDeLogs()
    {
        AdicionarLog = log => repositorio.Add(log),
        TodosGet = () => repositorio
    };

    var indice = 78D;
    new Monitor(stub).AvaliarIndice(indice);

    Assert.AreEqual(1, repositorio.Count);
}

Tags: , ,

.NET Framework

Autenticação - Mix entre WebApi e Interfaces

by Israel Aece 16. April 2012 22:15

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

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

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

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

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

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

Tags: , ,

ASP.NET | Security

Co e Contra Variância em Interfaces

by Israel Aece 12. April 2012 21:25

Os parâmetros genéricos foram recursos que foram incluídos no C# em sua versão 2.0. Desde então, podemos criar classes, interfaces, delegates, etc., que podem determinar um ou vários parâmetros e, consequentemente, utilizá-los definindo o tipo que acharmos necessário. No momento da criação/uso deste tipo, definimos o tipo do(s) parâmetro(s), e todos os membros em que o mencionamos passam a operar com ele, mas já fazendo diversas verificações ainda em tempo de compilação.

A partir do momento que podemos definir qualquer tipo, é comum queremos mencionar tipos que estão relacionados por herança, mas apesar disso ser suportado, algumas coisas que são comuns e fazemos normalmente, são barrados se utilizarmos em conjunto com tipos genéricos. Um caso específico que quero mencionar aqui, é o uso deste tipo genérico com interfaces. Para melhor ilustrar isso, vamos nos basear na estrutura de classes abaixo:

Note que Documento serve como base para todo e qualquer documento controlado pelo sistema. A partir deste momento, podemos criar interface que será responsável por definir um criador de objetos, e o tipo passa a ser determinado pelo parâmetro genérico T. Note que T é usado como retorno pelo método Criar.

interface ICriador<T>
{
    T Criar();
}

Com esta interface, podemos construir uma classe que representará o criador de objetos padrão do sistema, e para demonstração, tudo o que vamos fazer é instanciar o tipo definido em T, o que nos obriga a defnir uma constraint, ou seja, que o tipo T possua um construtor público.

class CriadorPadrao<T> : ICriador<T> where T : new()
{
    public T Criar()
    {
        return new T();
    }
}

A ideia desta classe, é concentrar a criação do objetos, ou melhor, dos documentos utilizados pelo nosso sistema. Sendo assim, como queremos trabalhar da forma mais genérica possível, ou seja, não quero lidar diretamente em meu código com ICriador<Cnpj>, ICriador<Cpf>, etc., isso me obriga a criar uma variável do tipo ICriador<Documento> (Documento é a classe base). Com isso, a qualquer momento atribuimos à esta variável a instância do criador genérico, apontando em T o tipo Cnpj, Cpf, etc., assim como sugere o código abaixo:

ICriador<Documento> c = new CriadorPadrao<Cnpj>();
Console.WriteLine(c.Criar());

Apesar de CriadorPadrao implementar a interface ICriador, e mesmo pelo fato de Cnpj (tipo genérico definido em T) herdar de Documento, o C# não permite a compilação deste código. O fato aqui é que toda interface genérica, até a versão 3.0 do C#, é sempre invariante. Apesar dos tipos - isoladamente - estarem relacionados, CriadorPadrao<Cnpj> não implementa a interface ICriador<Documento>, o que viola a regra do polimorfismo.

A versão 4.0 do C# introduziu um recurso chamado de covariância. Ele nos permitirá, com um ligeira mudança na interface, fazer com que o código acima seja compilado e executado com sucesso. A mudança qual me refiro, é a introdução da keyword "out" antes do tipo genérico T, assim como mostrado abaixo:

interface ICriador<out T>
{
    T Criar();
}

Isso dirá ao compilador que T somente será usado como retorno de métodos e/ou propriedades de somente leitura. Como o CriadorPadrao<Cnpj> vai retornar a instância da classe Cnpj no método Criar, ela pode ser acessada através da interface ICriador<Documento>, afinal, Documento é a classe base dela. Se definirmos na interface um parâmetro do tipo T, como o acesso à instância é através de ICriador<Documento>, poderia entrar qualquer coisa, ou seja, uma instância da classe Cnh, o que fará com que uma exceção seja disparada. Abaixo temos uma imagem que ajuda a entender:

Em um outro cenário, poderíamos ter uma interface que ao invés de retornar, passa a receber um tipo T. Dado um tipo, a interface define a estrutura de validação, que em seu método Validar recebe um parâmetro T, e devolve um bool indicando o resultado da validação. Abaixo temos a definição desta interface:

interface IValidador<T>
{
    bool Validar(T documento);
}

Teremos também um validador padrão, que define a estrutura de validação genérica para qualquer tipo. Note que temos a classe ValidadorPadrao, que define T e propaga para a interface e, consequentemente, para o método Validar. Note que neste momento, o T está entrando.

class ValidadorPadrao<T> : IValidador<T>
{
    public bool Validar(T documento)
    {
        //Validação
        return true;
    }
}

Agora a situação é que temos em mãos um validador exclusivo para Cnpj, e atribuímos a ele a instância da classe ValidadorPadrao, definindo T como Documento, ou seja, a classe base de todos os documentos, incluindo o próprio Cnpj.

IValidador<Cnpj> v = new ValidadorPadrao<Documento>();
v.Validar(new Cnpj());

Ao compilar o código, novamente temos um erro. Novamente, apesar de ValidadorPadrao implementar a interface IValidador, a atribuição não será possível. Apesar de estarmos tomando cuidado de passar para o método Criar um Cnpj (que herda de Documento), isso daria margem para definir o validador com um tipo sem relação alguma, como por exemplo, uma string, e através do método Validar passar a instância de CNPJ, e durante a execução, um erro ocorreria porque não é possível fazer tal conversão.

Para resolver isso, temos a contravariância. Também com uma pequena mudança na criação da interface, teremos um código mais flexível. Aqui teremos que adicionar antes do parâmetro T a keyword "in", assim como é mostrado abaixo:

interface IValidador<in T>
{
    bool Validar(T documento);
}

Isso dirá ao compilador que T somente será usado como parâmetros de entrada em métodos e/ou propriedades de somente escrita. Como o ValidadorPadrao<Documento> vai receber uma instância da classe Documento no método Validar, ela pode ser definida através da interface IValidador<Cnpj>, afinal, Cnpj é um tipo de Documento. Se definirmos na interface uma saída do tipo T, como o acesso à instância do validor é através de IValidador<Cnpj>, poderia retornar qualquer coisa, ou seja, uma classe Cnh, o que fará com que uma exceção seja disparada, pois não é possível converter Cnh em Cnpj. Abaixo temos uma imagem que ajuda a entender:

Tags:

C#

Contratos Assíncronos no WCF 4.5

by Israel Aece 8. April 2012 19:33

Há algum tempo eu mencionei aqui como criar um contrato assíncrono para um serviço WCF. A finalidade deste tipo de contrato é permitir a sua implementação de forma, também, assíncrona, para que possamos tirar um hor proveito dos recursos (leia-se threads), do servidor onde o serviço estará sendo hospedado.

Como o formato segue o padrão estabelecido pelo .NET Framework, somos obrigados a construir o contrato nos mesmos moldes do padrão definido por ele, ou seja, um par de métodos Begin/End. Além disso, ainda temos a necessidade de uma eventual implementação da interface IAsyncResult, callbacks, etc., ou seja, com toda a complexidade que estamos acostumados quando precisamos lidar com programação assíncrona no .NET.

As linguagens (C# e VB.NET) redefiniram a forma como escrevemos código assíncrono, e para tirar proveito disso, o WCF sofreu algumas mudanças internas, e agora a criação e implementação de contratos assíncronos são bem mais fáceis de serem implementados do que anteriormente.

Apesar das mudanças serem internas, para que seja possível esse tipo de utilização, algumas regras são exigidas ao (re)escrever o contrato. É necessário que a operação retorne um objeto do tipo Task (quando a mesma não retorna nenhum resultado) ou Task<T> (quando a mesma deve retornar um resultado (T refere-se ao tipo de resultado)). Abaixo temos a interface que define o contrato do serviço:

[ServiceContract]
public interface IContrato
{
    [OperationContract]
    Task<string> Ping(string value);
}

Ao implementar esse contrato na classe que representará o serviço, entre em cena as keywords do C# que faz toda a mágica para executar de forma assíncrona: async e await, quais já falamos aqui, e que em conjunto com os ajustes internos que a Microsoft fez no WCF (a crição de um operation invoker chamado TaskMethodInvoker), faz com que a operação seja executada sem qualquer grande impacto ao desenvolvedor. Abaixo temos um exemplo de implementação do contrato acima criado:

public class Servico : IContrato
{
    public async Task<string> Ping(string value)
    {
        return await Task.Factory.StartNew(() => value + " ping");
    }
}

Em termos que hosting, nada é necessário. Por fim, como já mencionado, em tempo de execução, teremos uma melhor reusabilidade das threads, o que nos permite executar algum recurso custoso, como por exemplo, chamado à bancos de dados, outros serviços, sem que a thread fique bloqueada esperando pelo resultado que não depende das capacidades do processamento local.

Já o consumo por parte de uma aplicação também .NET, temos uma ligeira mudança. Trata-se de uma nova opção chamada "Generate task-based operations". Ao efetuar a referência para um serviço e se esta opção estiver selecionada, fará com que a versão assíncrona das operações do proxy, sejam criadas utilizando o modelo baseado em tasks. Enquanto a outra opção, fará com que ele crie no modelo tradicional, ou seja, baseado em eventos XXXCompleted para cada uma das operações expostas pelo serviço. A imagem abaixo ilustra esta nova opção:

Tags: , ,

Async | WCF

Powered by BlogEngine.NET 1.5.0.0
Theme by Mads Kristensen

Sobre

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

Twitter

Host