NVarchar e NHibernate

Pode não ser novidade, mas as vezes podemos cair em algumas armadilhas que se não ficarmos atentos, podemos ter problemas de performance relacionados à campos do tipo de dado string. Apesar de focar o artigo no NHibernate, não é um problema somente dele, na verdade, acaba sendo mais um problema do banco de dados, pois ele pode acontecer independente se estiver ou não utilizando algum ORM na aplicação. Considere as consultas abaixo:

SELECT * FROM Duplicata WHERE PrefixoDoCnpj = N'111111111'
SELECT * FROM Duplicata WHERE PrefixoDoCnpj = '111111111'

O campo PrefixoDoCnpj é um campo do tipo varchar(11) na base de dados. Temos também um índice sobre este campo para otimizar as pesquisas por ele, afinal, é muito comum querer retornar todas as duplicatas de um determinado CNPJ. A única diferença que se nota em ambas as consultas é que a primeira tem o caractere “N” antes do valor do parâmetro. Isso serve para indicar ao SQL Server que o tipo de dado é nvarchar. Ao rodar as consultas, a primeira será muito mais lenta que a segunda versão, que utiliza o mesmo tipo de dado da coluna (varchar). Para entender melhor a diferença, vamos analisar os planos de execução:

nhnvarchar

Na primeira consulta, onde o parâmetro tem um tipo de dados diferente do tipo de dado da coluna, ele está fazendo um index scan, obrigando o SQL Server a tocar em cada uma das linhas do índice e fazer a conversão implícita de cada um dos valores (pode-se perceber isso na imagem acima), e sendo assim, o custo está diretamente associado à quantidade de linhas que a tabela tenha. Já a segunda consulta, o SQL Server opta por fazer uso do index seek, que recorre a forma de pesquisa onde ele extrai diretamente os registros que satisfazem o critério desejado.

Tudo o que vimos acima tem a ver exclusivamente com SQL Server. Se optarmos por utilizar o NHibernate para que ele faça a geração da base de dados a partir do nosso domínio, ao utilizar as configurações padrão, todos os campos strings serão mapeados como Unicode, ou seja, nvarchar. Além dos problemas de performance que vimos acima, por aceitar caracteres Unicode, precisamos de mais espaço de armazenamento, e dependendo do tipo de aplicação que está se desenvolvendo, isso não é necessário. E ainda, se criamos scripts manuais para a criação/manutenção de itens da base dados, optando pelo tipo de dado varchar e no NHibernate sermos omissos em relação à isso, o problema da degradação da performance acontecerá.

Para deixarmos explícito para ao NHibernate que ele deve utilizar varchar ao invés de nvarchar, podemos definir o tipo de dado da propriedade como AnsiString. Isso indicará ao SQL Server a tratar esta coluna da forma que desejamos (varchar), e além disso, podemos já definir o atributo sql-type para ser utilizado na geração do scripts de criação da base de dados se isso for necessário.

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="AppDeExemplo" namespace="AppDeExemplo">
  <class name="Sacado">
    <id name="PrefixoDoCnpj" length="11" type="AnsiString">
      <column name="PrefixoDoCnpj" sql-type="varchar(11)" length="11" />
      <generator class="assigned" />
    </id>
    <!-- Demais Configurações -->
    <bag name="Duplicatas">
      <key column="PrefixoDoCnpj" />
      <composite-element class="Duplicata">
        <!-- Demais Configurações -->
      </composite-element>
    </bag>
  </class>
</hibernate-mapping>
Publicidade

Segregando Requisições no ASP.NET

No ASP.NET Core temos o conceito de middlewares, que nada mais são que plugins que podemos acoplar à execução para que eles sejam executados a medida em que uma nova requisição chega para o serviço ou para o site. Além de vários que já foram criados pela Microsoft, a criação destes middlewares é extremamente simples, e é a principal forma que temos de interceptar o momento antes e/ou depois das requisições.

Durante a inicialização da aplicação, devemos realizar as configurações necessárias para que ela funcione, e é neste momento que montamos o pipeline por onde cada uma delas deverá passar, e isso quer dizer que faremos uso constante de middlewares, mesmo que não se esteja explicitamente claro no código que vamos escrever. A execução ocorre de forma linear, onde a requisição é entregue para o primeiro middleware e este é responsável por fazer alguma atividade e passar adiante a requisição (leia-se para o middleware interno). Abaixo temos um exemplo de um simples middleware; note que temos algumas convenções que precisam ser respeitadas, tais como: receber no construtor o próximo middleware, ter o método chamado Invoke que será disparado pelo ASP.NET no momento adequado. É dentro deste método que você define quando quer invocar o próximo middleware.

public class LoggingMiddleware
{
    private readonly RequestDelegate next;

    public LoggingMiddleware(RequestDelegate next)
    {
        this.next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        //Ação Antes
        await next(context);
        //Ação Depois
    }
}

O problema aqui é que podemos hospedar na mesma aplicação dois conteúdos que demandam diferentes rotinas e características. É comum encontrarmos aplicações que expõe uma API web, e na mesma aplicação, fornece o acesso à um pequeno site com a documentação, tutoriais, central de suporte para a mesma. Do lado da API, é comum termos log de acesso, telemetria, controle de transações, etc., enquanto do “lado do UI” da aplicação, necessitamos de outros recursos, como a exposição de conteúdos estáticos e geração de HTML.

O ASP.NET possibilita uma forma de segregar as requisições (branch), roteando cada uma delas de acordo com um critério e, que se atendido, podemos customizar um pipeline de middlewares exclusivo para aquele cenário. Isso evita ter um único pipeline com todos os passos e ter que dar by-pass de acordo com a requisição que estamos processando naquele momento exige. Para isso, podemos recorrer ao método Map da interface IApplicationBuilder. Em sua versão mais simplista, ele aceita uma string que permite especificarmos a URL que, se atendida, deverá ser executada utilizando a configuração que especificamos no segundo parâmetro deste mesmo método. Há uma variação deste método chamado MapWhen, que nos permite inspecionar outros itens da requisição (headers, por exemplo) para tomar a decisão se deve ou não ser processada por aquele pipeline.

No exemplo abaixo, se a requisição conter /commands na URL, então o middleware de logging será disparado, na sequência o de transações, e por fim, a ação do controller será executada. Já quando a requisição for para /help, estamos permitindo o acesso à arquivos estáticos (imagens, PDFs, etc.) e também o uso do MVC para renderizar HTML com o conteúdo da documentação da API:

public void Configure(IApplicationBuilder app)
{
    app.Map("/commands",
        config =>
            config
                .UseMiddleware<LoggingMiddleware>()
                .UseMiddleware<TransactionMiddleware>()
                .UseMvc());

    app.Map("/help", 
        config => 
            config
                .UseMvc()
                .UseStaticFiles());
}

Se desejar ter acesso ao código completo deste artigo, consulte este endereço.

Middlewares para Comandos

Quando optamos por separar a leitura da escrita em nossa aplicação, é comum adotarmos o padrão CQRS. Entre os vários conceitos que temos, um deles é a criação de comandos, que nada mais são do que classes que expressam a intenção do usuário em alterar, criar ou excluir alguma informação. O comando é definido através de uma classe, que traz informações (dados) sobre a ação a ser executada. Ele é passado para o que chamamos de command handler, que é o tratador deste comando, ou seja, ele coordena todas as ações sobre aquela entidade. E, da mesma forma, também é implementada através de uma classe (apesar de haver algumas variações). Em geral, a relação um tratador para cada comando.

O código abaixo exibe um exemplo simples disso. A classe Command não traz qualquer informação adicional, é apenas uma convenção; já a interface IHandler<T> define a estrutura que todo tratador de comando deverá ter, ou seja, o método Handle. É no interior deste método que recorremos ao repositório para adicionar/remover a entidade, manipular, etc.

public class CadastrarUsuario : Command
{
    public string Nome { get; set; }
}

public class CadastrarUsuarioHandler : IHandler<CadastrarUsuario>
{
    public CadastrarUsuarioHandler(IRepositorioDeUsuarios repositorio) { }

    public void Handle(CadastrarUsuario message)
    {
        Console.WriteLine("Cadastrando o usuário " + message.Nome);
    }
}

Para manter a simplicidade, este código está apenas escrevendo o nome do usuário na tela. Em um ambiente real, é provável termos que incrementar isso. Para citar alguns exemplos, é comum ter a necessidade de realizar logs, mensurar o tempo gasto na operação, proteger as ações através de uma transação, etc. A partir do momento que começarmos a incorporar essas atividades em nosso tratador, ele começará a ficar poluído, e o pior, começa a ter mais de uma responsabilidade além daquela para qual ele foi criado. Note o mesmo tratador que temos acima, contendo estes incrementos:

public class CadastrarUsuarioHandler : IHandler<CadastrarUsuario>
{
    public CadastrarUsuarioHandler(
        ILogger logger, 
        ITimer timer, 
        IUnitOfWork transaction, 
        IRepositorioDeUsuarios repositorio) { }

    public void Handle(CadastrarUsuario message)
    {
        this.timer.Start();
        this.logger.Info("Início");

        using (this.transaction)
        {
            this.repositorio.Salvar(message.Nome);
            Console.WriteLine("Cadastrando o usuário " + message.Nome);
        }

        this.logger.Info("Fim");
        this.timer.Stop();
    }
}

Mesmo que estamos recebendo as implementações do mundo exterior, a classe CadastrarUsuarioHandler está manipulando mais coisas do que deveria. Quando criarmos um segundo comando, teremos que repetir todos estes códigos, ficando sujeito a erros e com pouca reusabilidade.

O melhor a fazermos aqui é remover todo este código de cross-cutting, deixando o tratador do comando responsável apenas por criar e armazenar o usuário na base de dados através do repositório. Todas essas outras – importantes – atividades podem ser delegadas para classes que circundam todos os tratadores da aplicação, não ficando restrito a apenas um, e a partir daí, tendo um ponto central para isso, fica fácil a manutenção e eventual ajuste na interface dos componentes, já que não precisamos sair refatorando em diversos lugares da aplicação.

Uma das técnicas para isso, é criar um pipeline de funcionalidades, onde o item mais baixo de ações é a execução do tratador do comando. Até ele chegar no tratador propriamente dito, ele passaria pelas funcionalidades de log, timer e transação, deixando o ambiente todo preparado para a execução da atividade principal. A ideia é criar middlewares, próximo ao que temos no ASP.NET Core, para que possamos acoplar ou desacoplar alguma funcionalidade quando necessário. Além da extensibilidade, temos uma separação bem definida do que cada middleware deve fazer, sem um afetar no trabalho doutro. A imagem abaixo ilustra o exemplo:

commandhandlermiddleware1

O primeiro passo é a criação da interface que irá definir a estrutura de um middleware. Basicamente ele fornecerá um método chamado Execute, que além da instância do comando a ser executado, ela também recebe o método a ser executado na sequência. Opcionalmente, você pode optar por receber o delegate da próxima ação no construtor do middleware.

public interface IMiddleware
{
    void Execute(Command command, Action<Command> next);
}

A partir daí podemos ir criando os middlewares necessários para a nossa aplicação. Abaixo temos o exemplo do TimerMiddleware, que utiliza um Stopwatch para mensurar o tempo gasto na execução do comando. É importante notar que podemos ter códigos sendo executado antes e depois da próxima ação.

public class TimerMiddleware : IMiddleware
{
    public void Execute(Command command, Action<Command> next)
    {
        var timer = Stopwatch.StartNew();
        Console.WriteLine("[INFO] - Início - {0:HH:mm:ss}", DateTime.Now);

        try
        {
            next(command);
        }
        finally
        {
            timer.Stop();
        }

        Console.WriteLine("[INFO] - Fim - {0:HH:mm:ss} - Tempo Decorrido: {1}", 
            DateTime.Now, timer.Elapsed);
    }
}

Só que este middleware por si só não funciona. Temos agora que criar uma estrutura que consiga receber os middlewares e, consequentemente, montar uma cadeia de chamadas na ordem desejada para execução. A ideia é receber todos os middlewares necessários através do construtor do pipeline, e com isso, já criar uma sequência de execução, para que ela já esteja pronta quando chegar para o pipeline um novo comando. É importante notar aqui que neste cenário, o command bus (mencionado em arquitetura CQRS) é implementado como um middleware.

public class Pipeline
{
    private Action<Command> middlewareChain;

    public Pipeline(params IMiddleware[] middlewares)
    {
        this.middlewareChain = BuildChain(middlewares.Reverse().ToArray());
    }

    private static Action<Command> BuildChain(IMiddleware[] middlewares)
    {
        Action<Command> chain = command => { };

        foreach (var middleware in middlewares)
        {
            var temp = chain;

            chain = command => middleware.Execute(command, temp);
        }

        return chain;
    }

    public virtual void Handle<T>(T command) where T : Command
    {
        this.middlewareChain(command);
    }
}

Se quiser postergar a criação da cadeia de chamada para a primeira execução, podemos declarar o campo middlewareChain como Lazy<T>. E, por fim, basta instanciarmos o pipeline de acordo com a nossa estrutura de middlewares necessária para a aplicação, e a partir daí, passar os comandos que estão sendo requisitados pelos usuários. Novamente, note que o middleware CommandHandlerMiddleware é o último da lista:

var pipeline = 
    new Pipeline(
        new TimerMiddleware(), 
        new LoggingMiddleware(), 
        new TransactionMiddleware(), 
        new CommandHandlerMiddleware());

pipeline.Handle(new CadastrarUsuario() { Nome = "Israel" });

O código na íntegra está disponível neste link.

Além dos Tipos Primitivos

Ao criar tipos customizados para a aplicação, é comum utilizarmos os tipos primitivos da linguagem (inteiro, data, decimal, etc.) para especificar os campos que ele deverá conter, podendo trabalhar internamente ou externamente com estas informações. Se não nos atentarmos no momento da criação, é capaz de inflarmos o novo tipo com uma porção de propriedades, que muitas vezes podem estar relacionadas, e prejudicando assim a interface exposta para os consumidores.

Além disso, podemos perder parte do encapsulamento, pois se deixarmos para o consumidor combinar os campos para testar uma condição, pode ser que em algum momento ele se esqueça de avaliar de forma correta e, consequentemente, ter um resultado inesperado. Para exemplificar, considere a classe abaixo:

tipos1

Note que as propriedades estão divididas nas cores vermelha e azul. As propriedades em vermelho dizem a respeito do vencimento do boleto, enquanto as propriedade em azul se referem ao valor do título. O valor a ser pago pelo título é o valor bruto deduzindo o abatimento e o desconto (desde que esteja sendo pago antes da data limite para o mesmo). Já o vencimento agrupa tudo o que é necessário para indicar a real data de pagamento e/ou a quantidade de dias que falta para vencer ou que está vencido.

Se o consumidor quiser saber a data real de vencimento terá que fazer esta análise; se ele quiser saber o valor real do pagamento (deduzindo os descontos), terá que calcular. E o pior, isso deverá ser replicado para todos os pontos da aplicação que precisar disso. Uma solução seria criar propriedades de somente leitura na classe Boleto e já retornar os valores calculados. Só que fazendo isso, voltamos ao problema inicial: comprometer a interface pública do tipo. Mesmo que estivermos confortáveis em prejudicar a interface, pode ter outros tipos dentro do nosso domínio que precisa também lidar com isso (uma nota promissória, por exemplo, também tem vencimento), e tornamos a recriar tudo isso lá.

Para centralizar as regras, padronizar o consumo e reutilizar quando necessário, o ideal é abrir mão dos tipos primitivos e passar a criar tipos específicos para o nosso domínio, que agrupe os campos e forneça os dados já calculados, para que seja possível o consumo unificado das informações.

tipos2

Depois disso, a nossa classe Boleto fica bem mais enxuta, e a medida que vamos se aprofundando nas propriedades, chegamos nos mesmos dados, dando mais legibilidade e tendo a mesma riqueza de informações que tínhamos antes.

public class Boleto
{
    public Vencimento Vencimento { get; set; }
    public Valor Valor { get; set; }
}

var boleto = new Boleto()
{
    Vencimento = DateTime.Now.AddDays(5),
    Valor = 1250.29M
};

Note que se ajustarmos os operadores (overloading), conseguimos converter tipos primitivos em tipos customizados, conforme é possível ver acima, e tornar ainda mais sucinto o código.

Por fim, os ORMs que temos hoje permitem a serialização de todo o tipo ou de parte dele. Fica a nosso critério o que armazenar, ou seja, se optamos apenas pelos dados que originam o restante ou se armazenamos tudo o que temos, mas não é uma decisão fácil de tomar. Se optar por armazenar tudo, você ocupará mais espaço em disco; em contrapartida, se guardar apenas os dados que originam o restante e utilizar algum outro mecanismo para extração dos mesmo (DAL) sem passar pelo domínio, você não conseguirá reconstruir algumas informações sem replicar a regra na sua camada de leitura.

Rescrevendo Controllers

Codificar as ações (métodos) dentro de um controller não é uma tarefa difícil. A implementação varia muito, e todas elas podem ser consideradas corretas se atingirem o objetivo esperado. A finalidade deste vídeo é apresentar uma forma alternativa para a escrita de controllers e ações, mantendo o mesmo comportamento, porém organizando, estruturando e reaproveitando melhor os códigos que serão executados.

A ideia é mostrar uma outra forma para escrever controllers do ASP.NET MVC ou Web API, mas o conceito pode ser estendido para outros tipos de aplicação que estão além do mundo web.

Eventos de Domínio – Outra Opção de Disparo

Nos artigos anteriores falamos sobre a geração e consumo de eventos de domínio. Entre os assuntos abordados, discutimos os tratadores, que nada mais são que classes que são executadas reagindo ao evento que foi disparado. Ainda falando sobre os tratadores, abordamos a forma de descobrir os tratadores que fazem parte da aplicação (estática ou dinâmica) bem como a possibilidade de incluir novos tratadores em tempo de execução.

Para recapitular, temos a classe DomainEvents, qual utilizamos para disparar os eventos. Nos exemplos anteriores, esta classe estava sendo utilizada no interior das entidades, que quando era detectado a necessidade de disparo de algum evento, recorria ao método Raise, informando o tipo do evento e suas respectivas informações.

public void Lancar(Lancamento lancamento)
{
    var saldoAnterior = this.Saldo;

    this.lancamentos.Add(lancamento);
    this.Saldo += lancamento.Valor;

    DomainEvents.Raise(
        new SaldoDaContaAlterado(this.NomeDoCliente, saldoAnterior, this.Saldo));
}

O problema desta técnica é que a entidade além de criar o evento, também está sendo responsável por disparar ele, e se algum problema acontecer depois do disparo de evento que notifica a alteração do saldo, não é fácil desfazer o que já foi realizado pelo(s) tratador(es). Existem situações em que não dá para assegurar que depois do evento disparado as informações serão corretamente persistidas sem que algum erro ocorra. Considere o exemplo de código a seguir:

var repositorio = new RepositorioDeContas();

var cc = new ContaCorrente("Israel Aece");
cc.Lancar(new ContaCorrente.Lancamento("Pagto de Energia", -1000));

repositorio.Atualizar(cc);

Conforme vimos anteriormente, o método Lancar dispara o evento e o tratador adiciona o cliente para monitoramento. Imagine agora que ao invocar o método Atualizar do repositório, algum exceção ocorra. A complexidade para ir até o monitor e desfazer a inserção do cliente seria muito custosa e de difícil implementação. Isso poderia piorar ainda mais se estivermos trabalhando entre contextos distintos, que podem estar fisicamente separados.

Felizmente temos uma alternativa para melhorar a implementação e o disparo dos eventos, combinando isso com o repositório da entidade. Ao invés das entidades gerarem e dispararem os eventos, criamos internamente uma coleção destes eventos para que ela vá armazenando todos os acontecimentos, e ao atualizar na base de dados, percorremos todos os eventos, disparando cada um deles. Para uma melhor reutilização de código, criamos uma classe base para todas as entidades, ou melhor, para os aggregate roots.

public abstract class Entidade
{
    private readonly IList<IDomainEvent> eventos = 
        new List<IDomainEvent>();

    protected void AdicionarEvento(IDomainEvent evento)
    {
        this.eventos.Add(evento);
    }

    public void RemoverEventos()
    {
        this.eventos.Clear();
    }

    public IEnumerable<IDomainEvent> Eventos
    {
        get
        {
            return this.eventos;
        }
    }
}

Internamente esta classe armazenará a coleção de eventos, representado por instâncias de classes que implementam a interface IDomainEvent. A implementação do método Lancar tem uma suave mudança, e passa a recorrer ao método AdicionarEvento (que é protected) para adicionar o evento que indica a alteração do saldo.

public void Lancar(Lancamento lancamento)
{
    var saldoAnterior = this.Saldo;

    this.lancamentos.Add(lancamento);
    this.Saldo += lancamento.Valor;

    this.AdicionarEvento(
        new SaldoDaContaAlterado(this.NomeDoCliente, saldoAnterior, this.Saldo));
}

Isso por si só não funciona. Conforme falamos acima, temos que mudar o repositório para que ele identifique a existência de eventos e dos dispare. Mas aqui vale observar que ele somente deverá fazer isso depois que a atualização na base de dados (INSERT, UPDATE ou DELETE) seja realizada com sucesso. Os tratadores agora podem realizar suas atividades sem a preocupação de que aquilo poderia, em algum momento, ser desfeito.

Para manter a simplicidade, implementei o disparo dos eventos diretamente no repositório de contas, mas é possível refatorar o repositório a fim de criar uma base para todos os repositórios da aplicação, reutilizando o disparo de eventos para todas as entidades, já que o processo será o exatamente o mesmo. O método DispararEventos deve ser chamado sempre que a adição, atualização ou exclusão for realizada, e assim iteramos pela coleção de eventos (exposta pela classe abstrata Entidade) e invocamos o método estático Dispatch da classe DomainEvents. Por fim, depois dos eventos disparados, removemos os mesmos da entidade, já que se alguma coisa nova acontecer a partir dali, estes já estão concluídos.

public class RepositorioDeContas : IRepositorio<ContaCorrente>
{
    public void Atualizar(ContaCorrente entidade)
    {
        //Atualizar Base de Dados

        DispararEventos(entidade);
    }

    private static void DispararEventos(Entidade entidade)
    {
        foreach (var evento in entidade.Eventos)
            DomainEvents.Dispatch(evento);

        entidade.RemoverEventos();
    }
}

O método Dispatch tem funcionalidade semelhante ao Raise, mas soa melhor neste cenário, já que aqui ele tem a função de delegar o disparo dos eventos criados pelas entidades para os tratadores. Ao contrário do método Raise, que é genérico, o método Dispatch lida diretamente com instâncias da interface IDomainEvent ao invés dos eventos concretos. Por fim, ele analise se o tipo do evento que o tratador implementa é igual ao evento disparado, e o executa.

public static void Dispatch(IDomainEvent @event)
{
    foreach (var handler in handlers)
        if (handler.GetInterfaces()
                   .Any(h => h.IsGenericType && h.GenericTypeArguments[0] == @event.GetType()))
            ((dynamic)Activator.CreateInstance(handler)).Handle((dynamic)@event);
}

Eventos de Domínio – Disparo e Consumo

No artigo anterior falamos sobre a criação e utilização de eventos de domínio. O artigo abordou até o momento do disparo do evento propriamente dito, através da classe DomainEvents, só que sem mostrar detalhes de sua implementação. Existem diversas formas de se implementar o método de disparo do evento, mas antes de falarmos sobre estas técnicas, precisamos abordar como se constrói os consumidores dos eventos.

Para especificarmos os tratadores, vamos criar uma interface que descreverá apenas um método: Handler. Só que trata-se de uma interface genérica, onde o tipo T deve ser alguma classe que obrigatoriamente implemente a interface IDomainEvent, e que para o exemplo que estamos utilizando e evoluindo é a classe SaldoDaContaAlterado.

public interface IHandler<T> 
    where T : IDomainEvent
{
    void Handle(T @event);
}

Com a interface criada, temos que implementar a mesma em classes que serão consideradas os tratadores dos eventos, substituindo o tipo T por algum evento que nosso domínio define e estamos interessados em sermos notificados quando ele acontecer. Dentro da implementação do método Handle ficamos livres para executar tudo o que for necessário para aquele contexto, e que no nosso caso, é colocar “uma lupa” sobre o cliente que está com saldo negativo. Note que como parâmetro do método Handle temos (ou deveríamos ter) todas as informações necessárias a respeito do que ocorreu.

public class MonitorDeClientes : IHandler<SaldoDaContaAlterado>
{
    public void Handle(SaldoDaContaAlterado @event)
    {
        if (@event.SaldoAtual < @event.SaldoAnterior)
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine(
                "Monitorando o Cliente {0}. Saldo: {1:N2}",
                @event.NomeDoCliente,
                @event.SaldoAnterior);

            Console.ResetColor();
        }
    }
}

Uma vez que a classe concreta está criada e implementada, precisamos acopla-la a execução para que ela seja executada. Agora fazemos o uso da classe DomainEvents para acomodar a relação dos eventos de domínio. Aqui temos duas formas de proceder, sendo uma lista de tratadores estáticos ou de tratadores dinâmicos. Os tratadores estáticos permitem à aplicação já identificar todos os tratadores existentes, em outras palavras, podemos utilizar Reflection para encontrar todas as classes que implementam a interface IHandler<T> e adiciona-las a coleção de tratadores da aplicação, e também via Reflection, instanciarmos essas classes que representam os eventos toda vez em que ele for disparado pela domínio.

public static class DomainEvents
{
    private static List<Type> handlers = new List<Type>();

    static DomainEvents()
    {
        handlers =
            (
                from t in Assembly.GetExecutingAssembly().GetTypes()
                from i in t.GetInterfaces()
                where
                    i.IsGenericType &&
                    i.GetGenericTypeDefinition() == typeof(IHandler<>)
                select t
            ).ToList();
    }

    public static void Raise<T>(T @event) where T : IDomainEvent
    {
        handlers.ForEach(h =>
        {
            if (typeof(IHandler<T>).IsAssignableFrom(h))
                ((IHandler<T>)Activator.CreateInstance(h)).Handle(@event);
        });
    }
}

O uso externo da classe ContaCorrente não muda em nada, ou seja, continuamos interagindo com os métodos públicos que ela expõe. Como a varredura em busca por classes que implementam a interface IHandler<T> está no construtor estático da classe DomainEvents, tão logo quando a aplicação for inicializada os tipos serão identificados e adicionado, e quando o método Raise for invocado quando um lançamento de débito ou crédito ocorrer, o nome do cliente e seu saldo serão apresentados na tela em cor vermelha.

var cc = new ContaCorrente("Israel Aece");
cc.Lancar(new ContaCorrente.Lancamento("Pagto de Energia", -1000M));

A outra opção que temos é a relação dinâmica de tratadores, onde também podemos utilizar Reflection para descobrir os tratadores que implementam a interface IHandler<T>, porém há a possibilidade de dinamicamente adicionar novos tratadores em tempo de execução de acordo com a necessidade através do método Register. O método Raise agora já não instancia dinamicamente o tratador, ou seja, isso é responsabilidade do código que o consome, dando a possibilidade de fazer uso da instância antes e depois se desejar, o que pode ser útil durante os testes para saber se o evento foi o não disparado.

public class MonitorDeClientes : IHandler<SaldoDaContaAlterado>
{
    public readonly List<string> ClientesMonitorados = new List<string>();

    public void Handle(SaldoDaContaAlterado @event)
    {
        if (@event.SaldoAtual < @event.SaldoAnterior)
            this.ClientesMonitorados.Add(@event.NomeDoCliente);
    }
}

Neste modelo, para exemplificar, ao invés de escrever na tela o cliente monitorado, o adicionamos na coleção de clientes, que nada mais é que um campo da classe. E a classe DomainEvents também mudará a sua implementação para possibilitar o vínculo dinâmico de eventos, onde temos um dicionário que para cada tipo de evento uma coleção de delegates é criada.

public static class DomainEvents
{
    private static Dictionary<Type, List<Delegate>> handlers =
        new Dictionary<Type, List<Delegate>>();

    static DomainEvents()
    {
        handlers =
            (
                from t in Assembly.GetExecutingAssembly().GetTypes()
                where
                    !t.IsInterface &&
                    typeof(IDomainEvent).IsAssignableFrom(t)
                select t
            ).ToDictionary(t => t, t => new List<Delegate>());
    }

    public static void Register<T>(Action<T> handler) where T : IDomainEvent
    {
        handlers[typeof(T)].Add(handler);
    }

    public static void Raise<T>(T @event) where T : IDomainEvent
    {
        handlers[typeof(T)].ForEach(h => ((Action<T>)h)(@event));
    }
}

Por fim, o código que consome também sofrerá uma alteração para exibir o uso monitor antes e depois do evento que foi disparado.

var monitor = new MonitorDeClientes();
DomainEvents.Register<SaldoDaContaAlterado>(monitor.Handle);

var cc = new ContaCorrente("Israel Aece");
cc.Lancar(new ContaCorrente.Lancamento("Pagto de Energia", -1000));

Console.WriteLine("Qtde: {0}", monitor.ClientesMonitorados.Count);

Em ambas as técnicas é possível ter diversos tratadores para um mesmo evento gerado. Isso é comum e muito mais elegante do que em um simples tratador realizar mais tarefas do que ele deveria fazer. Se ele é responsável por monitorar, não deveria ser responsável por notificar o gerente que a conta de seu cliente ficou negativa. Nos tratadores também vale o princípio de responsabilidade única para garantir uma fácil manutenção e legibilidade.

Para finalizar, essas técnicas funcionam bem, mas existem alguns problemas funcionais que podem tornar o sistema propício a falhas. Mas isso será assunto do próximo artigo da série.

Eventos de Domínio – Geração

Os eventos de domínio nos permite identificar ações importantes que ocorrem em nossa aplicação e que desejamos divulga-la para os interessados. Por interessados, leia-se outras aplicações ou, principalmente, outros contextos que estão interligados e que reagem aos eventos para realizar uma outra atividade relacionada aquela que acabou de acontecer. Para um exemplo simples, considere uma conta corrente que ao atingir o valor negativo, a central de risco do banco deve ser acionada para entender o que está havendo com o cliente e, eventualmente, monitorar as suas atividades financeiras para evitar um prejuízo maior.

O lançamento de débito ou crédito se dá na conta corrente, e se a regra de monitoramento for atendida, temos que passar a monitorar o respectivo cliente. Incorporar eventos à classe correspondente, que neste caso é a classe que representa a conta corrente, ajudará em uma centralização de código, fácil manutenção e, principalmente, agregando à ela a responsabilidade de notificar que o saldo foi alterado (para cima ou para baixo). Competirá aos consumidores a usar a informação de acordo com a sua necessidade. O monitor de risco talvez não esteja interessado em uma conta que ficou “menos negativa”.

public class ContaCorrente
{
    //Outros membros ocultados

    public void Lancar(Lancamento lancamento)
    {
        var saldoAnterior = this.Saldo;

        this.lancamentos.Add(lancamento);
        this.Saldo += lancamento.Valor;
    }
}

Por agora, tudo o que o método acima faz é alteração da propriedade que armazena o saldo e inclui um novo lançamento na coleção interna. Depois do saldo alterado, chega o momento da conta corrente gerar o evento para notificar a alteração no saldo. A implementação padrão de eventos de domínio consiste na criação de uma marker interface, que geralmente não possui nenhum membro. Ao contrário do que acontece no .NET, onde os eventos são representados por delegates, no domínio utilizamos simples classes que implementam esta interface:

public interface IDomainEvent { }

A nomenclatura destas classes são sempre definidas no passado, que indicará que algo já ocorreu, por exemplo: NovoPedidoAdicionado, NotaFiscalEmitida, e para o nosso exemplo, SaldoDaContaAlterado. Vale lembrar que a nomenclatura deve expressar, e muito, exatamente o que ocorreu. E como já era de se esperar, todas as classes que representam eventos devem implementar a interface IDomainEvent que será útil para garantirmos a construção e uso dos tipos que envolvem a infraestrutura de eventos:

public class SaldoDaContaAlterado : IDomainEvent
{
    public SaldoDaContaAlterado(
        string nomeDoCliente, decimal saldoAnterior, decimal saldoAtual)
    {
        this.NomeDoCliente = nomeDoCliente;
        this.SaldoAnterior = saldoAnterior;
        this.SaldoAtual = saldoAtual;
    }

    public string NomeDoCliente { get; private set; }

    public decimal SaldoAnterior { get; private set; }

    public decimal SaldoAtual { get; private set; }
}

É importante notarmos que a classe que representa o evento possui algumas propriedades para descrever o que ocorreu, mas sempre temos que nos atentar em o que colocar ali, tentando manter a regra do mínimo possível necessário. Seguem algumas considerações importantes que devemos ter em mente durante a construção destas classes:

  • Entidades: é tentador colocar nestas propriedades a própria entidade que sofreu a alteração (ContaCorrente). Devemos ao máximo evitar isso, pois causará uma dependência destas classes para os interessados ao evento. Muitas vezes os eventos serão utilizados para comunicação entre contextos, e isso evitará a necessidade de referenciar a entidade (física e virtualmente). Tente optar sempre por tipos primitivos.
  • Imutabilidade: essas classes não devem ter qualquer funcionalidade (métodos), apenas os dados que correspondem ao evento gerado. As propriedades são de somente leitura e são abastecidas no construtor.
  • Ids: o Id da entidade pode ser definido no evento, mas isso só faz sentido se o consumidor já estiver colaborando com o gerador e tiver condições de recarregar a entidade, ou seja, ter acesso ao mesmo repositório. Caso o acesso não seja possível, teremos que incorporar na classe todas as informações necessárias para reportar a alteração, nem que seja necessário a duplicação de todas as informações da entidade.

Uma vez que os eventos já estão definidos, chega o momento de disparar. Como mencionado acima, o responsável pelo disparo será a própria classe que identifica a mudança, e que neste caso é a ContaCorrente, e sem qualquer análise de outra condição, dispara o evento informando que o saldo foi alterado. Note que ela irá recorrer à classe estática chamada de DomainEvents.

public class ContaCorrente
{
    //Outros membros ocultados

    public void Lancar(Lancamento lancamento)
    {
        var saldoAnterior = this.Saldo;

        this.lancamentos.Add(lancamento);
        this.Saldo += lancamento.Valor;

        DomainEvents.Raise(
            new SaldoDaContaAlterado(this.NomeDoCliente, saldoAnterior, this.Saldo));
    }
}

Agora é de responsabilidade da classe DomainEvents encontrar os consumidores deste tipo de evento e notifica-los da alteração. Há diversas técnicas que podemos utilizar na implementação da classe DomainEvents bem como em seus consumidores, mas que merece um artigo específico, e será abordado na sequência desta série.

HTTPS no Kestrel

Sempre quando pensamos em hospedar uma aplicação desenvolvida em ASP.NET logo nos vem a mente o IIS. Apesar de uma infinidade de recursos que ele possui, o novo ASP.NET traz nativamente uma forma de hospedar as aplicações em um processo fora do IIS (self-hosting), chamado de Kestrel, qual foi construído com a finalidade de ser multi-plataforma e vem ganhando bastante evidência com alguns testes que demonstram grandes resultados em termos de performance.

Aos poucos a Microsoft vem adicionado nele algumas funcionalidades para que ele incorpore tudo que é necessário para utilizarmos em ambientes de produção. A finalidade deste artigo é demonstrar como configurar a aplicação para suportar o uso do protocolo HTTPS e, consequentemente, proteger os recursos que serão expostos pela aplicação.

Como sabemos, independentemente da tecnologia ou servidor que utilizamos para as nossas aplicações, para o uso do HTTPS se faz necessário a compra de um certificado de alguma entidade publicamente conhecida, para que possamos instalar em nosso servidor e configurar a nossa aplicação para utiliza-lo para estabelecer um túnel seguro de comunicação entre o cliente e o servidor e vice-versa. Como o foco é demonstrar a configuração, vou utilizar um certificado de testes emitido por uma ferramenta, sem valor para uso em ambiente de produção.

O primeiro passa em nossa aplicação é indicar ao runtime que o hosting a ser utilizado é o Kestrel, e para isso, recorremos ao método UseKestrel. Em um dos seus overloads é possível acessar algumas configurações e entre elas a possibilidade de indicar que queremos que o HTTPS seja utilizado, que é expressado através do método de estensão UseHttps. Para fazer uso deste método é necessário a instalação de um pacote NUGET chamado Microsoft.AspNetCore.Server.Kestrel.Https.

Uma vez que o certificado está criado e armazenado em um arquivo PFX (que inclui a sua chave privada) e o pacote acima mencionado esteja instalado na aplicação, utilizamos o código abaixo para indicar o local onde o arquivo PFX referente ao certificado está localizado no disco; note também que o “12345” é a senha para que o ASP.NET possa acessar o certificado.

public class Program
{
    public static void Main(string[] args)
    {
        new WebHostBuilder()
            .UseKestrel(opts => opts.UseHttps(@”C:tempAppTesteMeuWebSite.pfx”, “12345”))
            .UseUrls(“http://localhost:5000/&#8221;, “https://localhost:5001/&#8221;)
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseStartup<Startup>()
            .Build()
            .Run();
    }
}

Ao rodar, a aplicação estará disponível para acesso tanto através do HTTP quanto HTTPS, porém em portas diferentes.

Transformação de Claims

Ao autenticar um usuário, nós podemos além de armazenar no token o seu nome, algumas outras propriedades que o descrevem, tais como: e-mail, papéis (roles), etc. Com isso, nós teremos diversas outras características dele além de apenas o nome e os papéis que ele possui dentro da aplicação.

Como sabemos, essas informações são expressadas através de claims. Ao autenticar, nós podemos criar uma coleção de claims contendo todas as informações sobre o respectivo usuário. Como as claims estão em todo lugar, o ASP.NET fornece um recurso específico que permite a transformação de claims, ou seja, além de utilizar informações que temos do lado do servidor para descrever o usuário, para complementar extraindo dados da requisição e incluir na coleção de claims.

Para customizar o tranformador, devemos implementar a interface IClaimsTransformer, e através do método TransformAsync podemos incrementar mais informações sobre o usuário e mais tarde utiliza-las para autorização de algum recurso específico. No exemplo abaixo, estamos extraindo a cultura (via header Accept-Language) da requisição e incluindo no ClaimsPrincipal gerado:

public class CultureToClaimTransformer : IClaimsTransformer
{
    public Task<ClaimsPrincipal> TransformAsync(ClaimsTransformationContext context)
    {
        var principal = context.Principal;

        if (principal.Identity.IsAuthenticated)
        {
            var culture = StringValues.Empty;

            if (context.Context.Request.Headers.TryGetValue(“Accept-Language”, out culture))
                ((ClaimsIdentity)principal.Identity).AddClaim(new Claim(“Culture”, culture.ToString()));
        }

        return Task.FromResult(principal);
    }
}

Só que a classe por si só não funciona. Precisamos incluir a mesma na execução, e para isso, recorremos ao método UseClaimsTransformation para indicar ao runtime do ASP.NET a classe que faz a transformação de claims. Depois do MVC devidamente configurado, estamos utilizando a autenticação baseada em cookies para o exemplo, indicamos a instância da classe CultureToClaimTransformer para a propriedade Transformer.

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddAuthentication();
        services.AddMvc();
    }

    
public void Configure(IApplicationBuilder app)
    {
        app.UseCookieAuthentication(new CookieAuthenticationOptions()
        {
            LoginPath = “/Aplicacao/Login”,
            ReturnUrlParameter = “ReturnUrl”,
            AutomaticAuthenticate = true,
            AutomaticChallenge = true
        });

        app.UseClaimsTransformation(
new ClaimsTransformationOptions()
        {
            Transformer = new CultureToClaimTransformer()
        });

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: “default”,
                template: “{controller=Aplicacao}/{action=Index}/{id?}”);
        });
    }
}

Depois de toda a configuração realizada, nós vamos codificar o nosso controller. Ele possui apenas dois métodos: um que exibe informações e o outro que onde de fato realizamos o login. O método que exibe as informações (Index) está decorado com o atributo AuthorizeAttribute, que não permitirá usuários não autenticados acessá-lo. Já o segundo método serve para autenticar o usuário; em uma aplicação real, este método deve receber as informações postadas em um formulário para validar primeiramente se o usuário existe (em uma base de dados, por exemplo), e caso verdadeiro, aí sim devemos proceder com a autenticação.

public class
AplicacaoController : Controller
{
    [Authorize]
    public IActionResult Index()
    {
        return View();
    }

    
public IActionResult Login()
    {
        HttpContext.Authentication.SignInAsync(
            CookieAuthenticationDefaults.AuthenticationScheme,
            new ClaimsPrincipal(
                new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, “Israel Aece”) }, 
                CookieAuthenticationDefaults.AuthenticationScheme))).Wait();

        
return Redirect(Request.Query[“ReturnUrl”]);
    }
}

Por fim, ao rodar a aplicação e exibir a coleção de
claims do usuário logado, nós teremos duas: uma com o nome do usuário e a outra com a cultura que foi passada pelo navegador que o usuário está utilizando para acessar a aplicação: