Virtualização do Reflection

Reflection é uma técnica que utilizamos no .NET para lidar diretamente com os metadados, ou seja, extrair quais são os campos, propriedades, métodos, eventos, atributos, etc., para que possamos criar um código dinâmico, com o intuito de inspecionar ou até mesmo alterar valores ou a execução baseado no que temos em cada um dos tipos.

Uma das técnicas utilizadas pelo próprio .NET Framework, e também por nós, é a criação ou utilização de atributos que nos permitem decorar em diversos membros, para que eles guiem a execução, permitindo ao consumidor destes tipos, a ler e interpretá-los de acordo com uma determinada regra. Para exemplificar, abaixo temos alguns casos de uso destas técnicas:

  • O Visual Studio utiliza atributos decorados nas propriedades das classes (controles), para exibir cada uma delas na janela de propriedades da IDE.
  • O WCF obriga a interface que define o contrato do serviço estar decorada com o atributo ServiceContractAttribute.
  • Utilizamos o atributo AuthorizeAttribute para refinar o acesso às ações dos controllers do ASP.NET MVC.
  • Alguma funcionalidade específica em vossa aplicação.

Partindo deste princípio, podemos ter um atributo customizado que utilizamos para decorar em propriedades de um determinado tipo. Esse atributo basicamente define um rótulo customizado para cada propriedade onde ele é aplicado. Abaixo temos o atributo e a classe já fazendo uso do mesmo:

public class Exibicao : Attribute
{
    public string Label { get; set; }
}

public class LinhaDeRegistro
{
    [Exibicao(Label = “Nome”)]
    public string Nome { get; set; }

    [Exibicao(Label = “Código”)]
    public int Codigo { get; set; }

    [Exibicao(Label = “Valor”)]
    public decimal Valor { get; set; }

    public DateTime DataDaOcorrencia { get; set; }
}

É importante dizer que o atributo por si só não serve para nada. Precisamos de um código que o consuma e faça alguma coisa com ele. Para isso, temos um método que percorre as propriedades do objeto, e para cada uma delas, verifica se existe o atributo recém criado, e se existir, exibe a informação formatada utilizando o rótulo que foi definido durante o desenvolvimento.

public static void ExibirColunas(Type type, object value)
{
    foreach (var p in new type.GetProperties())
    {
        var a = p.GetCustomAttribute(typeof(Attribute)) as Exibicao;

        if (a != null)
            Console.WriteLine(
                “{0}: {1}”, a.Label, p.GetValue(value, null));
    }
}

Com este método criado, podemos fazer o uso dele passando o objeto contendo as informações e também o seu tipo. Apesar de conseguir extrair o Type no interior do próprio método, optei por deixar propositalmente via parâmetro, que mais tarde isso fará sentido. Abaixo o código que chama este método:

var linha = new LinhaDeRegistro()
{
    Codigo = 1,
    Nome = “Israel”,
    Valor = 12000,
    DataDaOcorrencia = DateTime.Now
};

ExibirColunas(linha.GetType(), linha);

Ao rodar a aplicação, o resultado será:

Nome: Israel
Código: 1
Valor: 12000

Como percebemos, o valor da propriedade DataDaOcorrencia não é exibida. Mas faz sentido, pois ela não foi decorada com o atributo Exibicao que criamos acima. Para resolver isso, basta, também, decorar o atributo na propriedade, compilar e rodar, que a informação será exibida conforme o esperado. Mas como faremos isso, se a classe LinhaDeRegistro está em um outro assembly, onde não temos acesso ao código fonte?

Para sanar esse problema, podemos recorrer à classe CustomReflectionContext, que está debaixo do namespace e assembly System.Reflection.Context.dll. Esse assembly faz parte do .NET Framework 4.5, que externaliza as capacidades de reflection de um determinado objeto, sem a necessidade de recriar um modelo total para isso.

A implementação padrão da classe abstrata CustomReflectionContext, simplesmente serve como um wrapper, sem qualquer mudança em relação ao tradicional. Mas isso nos dá a chance de customizar a criação de um novo contexto de reflection, e sobrescrevendo alguns métodos, nós podemos adicionar, remover ou alterar atributos ou até mesmo adicionar novas propriedades aos tipos que estamos manipulando.

Para exemplificar a sua utilização, criamos um contexto customizado, onde sobrescrevemos o método GetCustomAttributes, identificamos se o membro trata-se da propriedade DataDaOcorrencia, e se for, retornamos um atributo Exibicao configurado conforme é necessário por nossa aplicação (ou seja, pelo método ExibirColunas).

public class ContextoParaExibicao : CustomReflectionContext
{
    protected override IEnumerable<object> GetCustomAttributes(MemberInfo member,
        IEnumerable<object> declaredAttributes)
    {
        if (member.Name == “DataDaOcorrencia”)
            return new[] { new Exibicao() { Label = “Data da Ocorrência” } };

        return base.GetCustomAttributes(member, declaredAttributes);
    }
}

Finalmente, depois da criação deste contexto, precisamos utilizá-lo, e para isso, o instanciamos e chamamos o método MapType, que recebe como parâmetro um objeto do tipo TypeInfo, que também novo no .NET 4.5, e caracteriza a parte de “reflection” de um determinado tipo. Como essa classe herda da classe Type, podemos utilizar o retorno deste método, e passar diretamente para o método consumidor, sem a necessidade de alterar nada em seu interior:

ExibirColunas(
    new ContextoParaExibicao().MapType(linha.GetType().GetTypeInfo()),
    linha);

Apesar de algumas soluções já existirem no .NET Framework (TypeDescriptor e PropertyDescriptor) para tentar extrair essas mesmas informações, provendo também tipos específicos para a customização da extração (ICustomTypeDescriptor), o time do .NET Framework/CLR decidiu incorporar isso diretamente no .NET Framework, o que pode ser utilizado por todos aqueles que desejam essa funcionalidade, de dentro ou fora da Microsoft.

Anúncios

Compressão no .NET Framework 4.5

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

Utilizando o DataReader Assincronamente

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
}

Microsoft Fakes no Visual Studio 2011

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

Claims em todo lugar

Há algum tempo eu falei aqui sobre o WIF (Windows Identity Foundation), que consiste em um framework para tornar o gerenciamento de identidades em aplicações .NET mais simples. Ele traz uma série de funcionalidades, que quando utilizado nas aplicações, nos permite lidar com a autenticação e autorização de uma forma mais poderosa, conseguindo inclusive, terceirizar/centralizar isso para uma outra aplicação.

O modelo de objetos do WIF, definia duas novas interfaces: IClaimsIdentity e IClaimsPrincipal, que herdavam de duas interfaces já existentes no .NET Framework desde a sua primeira versão (IIdentity e IPrincipal, respectivamente). Apesar de indiretamente compatíveis com os principals do .NET (WindowsPrincipal e GenericPrincipal), havia um trabalho extra a se fazer quando a conversão fosse necessária, ou melhor, quando a aplicação queria trabalhar com claims ao invés do modelo tradicional.

Com o .NET Framework 4.5, a Microsoft decidiu incorporar o modelo de claims diretamente no .NET Framework ao invés disso ser fornecido exclusivamente pelo WIF. A partir da versão 4.5, o .NET Framework passa a fornecer nativamente os tipos necessários para trabalhar com claims, e ainda, fez com que as classes WindowsPrincipal e GenericPrincipal herdem de ClaimsPrincipal e, consequentemente, toda e qualquer aplicação ao ser migrada para a versão 4.5 do .NET, automaticamente poderá fazer uso de claims. O diagrama abaixo mostra a hierarquia da herança entre essas classes:

System.Security.Claims é um novo namespace que foi adicionado ao .NET Framework, com a finalidade de agrupar os tipos disponíveis para realizar o trabalho via claims. Abaixo temos um exemplo de como podemos fazer o uso de claims em aplicações que utilizam, por exemplo, um modelo de autenticação customizado:

using System;
using System.Security.Claims;
using System.Security.Principal;

namespace App
{
class Program
{
static void Main(string[] args)
{
var principal =
new GenericPrincipal(new GenericIdentity(“Israel Aece”), new [] { “Admin”, “IT” });

foreach (var item in principal.Claims)
Console.WriteLine(“{0}: {1}”, item.Type, item.Value);
}
}
}

Utilizando o evento FirstChanceException

Dependendo da tecnologia que estamos utilizando, há opções diferentes para o tratamento global de exceções, onde na maioria das vezes, nos preocupamos em efetuar o log de exceções não tratadas pela nossa aplicação. Por exceção não tratadas, entendam que sejam aquelas exceções que são disparadas e não estão envolvidas por um bloco try/catch.

Aquelas exceções que sabemos como lidar, prontamente interceptamos e exibimos uma mensagem amigável para o usuário, podendo ele ou o sistema, resolver ou sugerir a solução para o mesmo. Muitas vezes, para essas exceções “amigáveis”, não nos preocupamos em catalogá-las e, consequentemente, não sabemos com qual frequência elas estão sendo disparadas. Informação essa que poderíamos utilizar para melhorar e tentar contornar o problema, para assim evitar que ela seja disparada frequentemente.

Como podemos perceber, há várias situações em que nos deparamos com o tratamento de exceções. Centralizar o tratamento facilita o log, mas não permite resolver o problema no local onde ela ocorre; já o tratamento local nos permite refinar a mensagem e como resolver o problema, mas acaba com uma explosão de blocos de tratamento de erros e, eventualmente, inclui um código para logar estas exceções.

Para facilitar isso, a partir da versão 4.0 do .NET Framework, temos um novo evento que foi adicionado à classe AppDomain, chamado de FirstChanceException. Esse evento é disparado momentos antes da CLR procurar dentro da call stack um tratador (bloco try/catch) para este tipo de exceção. Mesmo que o código que dispara a exceção estiver envolvido por um bloco catch com uma exceção específica, primeiramente o evento em questão será disparado, para em seguida, entregar a exceção para o respectivo tratador. Isso permitirá interceptar toda e qualquer exceção que aconteça, mesmo aquelas que já estejam devidamente tratadas.

É importante dizer que este evento é meramente informativo, ou seja, isso quer dizer que se a exceção não estiver sendo tratada, ela irá danificar a sua aplicação. Não há nenhum flag que nos permita definí-la como tratada. O código abaixo ilustra a sua utilização:

AppDomain.CurrentDomain.FirstChanceException += (obj, e) => EfetuarLog(e.Exception);
try
{
    throw new Exception(“Algum Erro.”);
}
catch (Exception)
{
    Console.WriteLine(“Tratando o Erro.”);
}

O atributo InheritedExport do MEF

A Microsoft incorporou no .NET Framework 4.0 o MEF (Managed Extensibility Framework), qual podemos utilizar para criar extensões em nossas aplicações e/ou utilizá-lo como um container de injeção de dependências. E ainda quando estava em suas primeiras versões, eu escrevi um artigo sobre ele, abordando os princípios básicos de sua utilização.

Basicamente o MEF trabalha com atributos, que decorados nos tipos envolvidos, importam ou exportam partes que são utilizadas pelo container para construir e, consequentemente, atribuir às classes que utilizam tais instâncias. Para exemplificar, veja o exemplo abaixo, onde temos uma interface que define a estrutura para logs de instruções em algum arquivo no disco:

public interface ILogger
{
    string Path { get; set; }

    void Write(string message);
}

E depois disso, temos as classes que implementam essa interface, criando os tipos concretos de acordo com a nossa necessidade. Abaixo temos essas implementações, e em cada classe que implementa a interface IFileLogger, explicitamente temos que decorá-las com o atributo ExportAttribute, para informar ao container que aquela classe é uma implementação de uma determinada interface.

[Export(typeof(IFileLogger))]
public class CsvLogger : IFileLogger { }

[Export(typeof(IFileLogger))]
public class XmlLogger : IFileLogger { }

Só que se tivermos várias implementações, estamos obrigados a especificar classe a classe esse atributo para que o runtime possa utilizá-las. A finalidade deste artigo é apenas para apresentar um atributo que também faz parte do MEF, chamado de InheritedExportAttribute, que pode ser aplicado diretamente na definição (interface), que diz ao container que todos aqueles que o implementarem, são candidatos a serem utilizados pela aplicação, e com isso, não há mais a necessidade de especificar classe a classe o atributo ExportAttribute.

[InheritedExport]
public interface ILogger
{
    string Path { get; set; }

    void Write(string message);
}

Utilizar este atributo faz com que todas as implementações sejam adicionadas ao container. Se você quiser trabalhar da forma inversa, ou seja, optar por marcar somente aquelas que não devem ser adicionadas, então você pode utilizar o atributo PartNotDiscoverableAttribute, que previne que a implementação não seja incluída no catalogo, e consequentemente, não utilizada pelo container. Exemplo:

[PartNotDiscoverable]
public class FakeLogger : IFileLogger { }