Aspect Oriented Programming ou Programação Orientada a Aspectos é um paradigma de programação que já existe há algum tempo, mas que ultimamente tem chamado bastante atenção da comunidade de desenvolvedores .NET. Ela é utilizada na separação e modularização de aspectos de Infraestrutura de um Software.

AOP é frequentemente utilizada para implementar recursos de Log, Tracing, Cache, Segurança, Concorrência ou Falhas. Existe um universo de soluções que pode ser implementado utilizando-se AOP e os exemplos que citei anteriormente são somente as soluções mais comuns.

Se é repetitivo, pode DEVE ser automatizado.

Paradigmas

  •  AOP não é:
    • Uma linguagem de programação;
    • Um recurso nativo em .NET (Ou até mesmo no Java);
    • Um substituto da programação orientada a objetos.
  • AOP é:
    • Um padrão de programação;
    • Uma ferramenta de trabalho em seus projetos;
    • Um complemento à programação orientada a objetos.

Modularidade

Como aspectos são construídos para solucionar problemas de Cross-Cutting Concerns*, estes mesmos aspectos na maioria das vezes podem ser transportados e reutilizados em outros projetos, sendo assim, existe a característica de modularidade neste padrão de desenvolvimento.

Quem nunca precisou de uma classe de Log que já havia utilizado em outro projeto?

Cross-Cutting Concerns* : São funcionalidades que não estão diretamente relacionadas ao domínio da aplicação ou às suas respectivas regras de negócio, mas que ainda sim, são importantes para o Software. Exemplos: Sincronização, logging, alocação de memória, transações, etc.

Tipos de AOP

  • Interceptação
    • Neste método é injetado em tempo de execução um  conceito de Cross-Cutting da aplicação. É uma forma não invasiva de modificação do caminho de execução do código, e deve ser utilizada quando o projeto estiver utilizando Injeção de Dependência, uma vez que você pode aplicar uma implementação de um interceptador a todas as classes do Assembly.
  • IL Weaving
    • Neste método a interceptação é feita durante o processo de compilação. Utiliza uma metodologia invasiva para alterar o caminho de execução do código. Pode ser aplicado em qualquer projeto mesmo que não esteja utilizando Injeção de Dependência.

Ferramentas disponíveis no Mercado

  • PostSharp
  • LOOM.NET
  • Aspect.NET
  • AspectDNG
  • DotSpect (.SPECT)
  • Spring.NET Framework
  • Seasar.NET
  • Aspect#
  • Puzzle.NAspect

Estudo de Caso Utilizando PostSharp

No exemplo a seguir demonstrarei como construir um recurso de log utilizando a biblioteca PostSharp. O método de AOP que utilizaremos é baseado em IL Weaving, portanto pode ser aplicado em qualquer projeto .NET independente da forma em que sua arquitetura foi concebida.

A ferramenta já possui alguns aspectos pré-construídos para que você possa simplesmente plugar e usar no seu projeto (Log, Undo/Redo, Threading, e outros). Ensinarei dessa forma primeiramente, e mais abaixo, no tutorial, vou explicar como você pode capturar a execução de processos de uma forma avançada e mais granular, para que você possa implementar da sua maneira qualquer aspecto customizado que quiser.

Instalando a Ferramenta

Antes de mais nada, precisamos instalar a ferramenta em nossa estação de desenvolvimento. Para isso, faça o download no link a seguir (Eu estou utilizando a versão gratuita, mas há também uma versão paga que conta com mais recursos) :

https://www.postsharp.net/download

Após efetuado o download, instale a ferramenta com as configurações padrões (Licença PostSharp Express se você quiser utilizar a versão FREE).

Se você tiver interesse em conhecer quais são os requisitos mínimos e compatibilidade da ferramenta em relação aos IDEs e Frameworks, confira o seguinte link:

http://doc.postsharp.net/requirements

Adicionando o aspecto de Log

Agora que temos a ferramenta instalada, podemos utilizar aspectos em quaisquer projetos que desejarmos. Eu criei um projeto do tipo “Console Application” apenas com um método de Soma a fim de ilustrar o artigo, mas você já pode utilizar em algum projeto pessoal ou profissional se quiser.

Clique sobre o nome do método que você deseja adicionar a opção de Logging, e uma sugestão de adicionar um aspecto de Logging irá aparecer conforme a ilustração abaixo:

AOP01

Selecione a opção do menu “Add Logging”. Conforme eu havia dito antes, existem outros aspectos já disponíveis para utilizarmos, mas vamos continuar com o aspecto de log.

Após selecionar a opção do menu, um Wizard de configuração irá se abrir. Selecione a opção “Default” para registrarmos toda vez que nosso método for chamado. Se quiser registrar apenas em exceções, existe a segunda opção “Exceptions”, mas vamos continuar com a “Default” para nosso tutorial. Veja a imagem ilustrativa abaixo:

AOP02

Após selecionarmos a opção “Default”, o próximo passo do Wizard nos pergunta qual serviço de log iremos utilizar para escrever nossos logs. Selecione a opção “Log4Net” e todos os registros serão autenticados em um arquivo TXT conforme iremos configurar mais a frente no tutorial.

AOP03

Após selecionarmos a opção “Log4Net” e apertar “Next”, um resumo da configuração será exibido. Aperte “Next” para que a configuração seja processada.

AOP04

Após terminado o processo de adição do aspecto, podemos clicar em “Finish” para fechar o Wizard. Perceba que mais bibliotecas foram incluídas no projeto. Um novo arquivo de configuração com a extensão “.psproj” foi adicionado ao nosso projeto, e este arquivo é referente as configurações do PostSharp. Veja como ficou nosso código do método:

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Resultado da soma => " + Somar(2, 2));
        }

        [Log]
        public static int Somar(int valorA, int valorB)
        {
            return valorA + valorB;
        }
    }

Perceba que o método foi decorado com o atributo “Log” do namespace “PostSharp.Patterns.Diagnostics”. Se quisermos adicionar o aspecto de log a outros métodos da aplicação, basta decorar os outros métodos com este atributo. Se quisermos, também podemos aplicar o aspecto direto na classe, e o mesmo aspecto será refletido em todos os métodos daquela classe. Existem algumas propriedades que também podemos configurar. Veja como fica o atributo de Log aplicado a todos métodos públicos de uma classe:

    [Log(AttributeTargetMemberAttributes = MulticastAttributes.Public)]
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Resultado da soma => " + Somar(2, 2));
        }

        public static int Somar(int valorA, int valorB)
        {
            return valorA + valorB;
        }
    }

Voltando a nossa configuração de log por método, se rodarmos a aplicação agora nada será registrado porque ainda não configuramos o Log4Net em nosso aplicativo. Para configurar o Log4Net, configure o seu “App.Config” ou “Web.Config” com a seguinte declaração:

  <configSections>
    <section name="log4net"
             type="log4net.Config.Log4NetConfigurationSectionHandler,Log4net"/>
  </configSections>
  <log4net>
    <root>
      <level value="DEBUG" />
      <appender-ref ref="LogFileAppender" />
    </root>
    <appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender">
      <param name="File" value="C:\temp\log.txt" />
      <param name="AppendToFile" value="true" />
      <rollingStyle value="Size" />
      <maxSizeRollBackups value="10" />
      <maximumFileSize value="10MB" />
      <staticLogFileName value="true" />
      <layout type="log4net.Layout.PatternLayout">
        <param name="ConversionPattern" value="%-5p%d{ yyyy-MM-dd hh:mm:ss} – %m%n" />
      </layout>
    </appender>
  </log4net>

E para finalizar a configuração do Log4Net, adicione a seguinte linha de código no método de inicialização do seu programa, ou no Application_Start do Global.Asax se estiver usando uma aplicação Web:

    log4net.Config.XmlConfigurator.Configure();

Pronto! Agora é só rodar a nossa aplicação, garantir que o método seja executado e conferir o arquivo .TXT que foi gerado no diretório “C:\temp” (Você pode alterar este diretório no XML de configuração do Log4Net). Veja como ficou registrado no meu projeto básico para o tutorial:

DEBUG 2015-08-21 11:17:19 – Entering: Program.Somar(2, 2)
DEBUG 2015-08-21 11:17:19 – Leaving: Program.Somar(2, 2) : 4

Nosso atributo de log está configurado e funcionando. Agora basta decorar nossos métodos ou classes e ver as execuções dos métodos sendo registradas.

Criando aspectos customizados

Não podemos negar a facilidade dos aspectos já prontos que o PostSharp nos disponibiliza, mas existem cenários onde precisamos escrever nossos próprios aspectos ou até mesmo aspectos que o PostSharp já nos disponibiliza mas que não atendem nossos requisitos.

Nessa situação nossa opção é codificar os nossos próprios aspectos, mas para nossa alegria, o PostSharp também nos dá essa opção.

Vamos criar um aspecto que tenha um comportamento parecido com o que fizemos acima, mas que escreva as mensagens de log em português com o formato que desejarmos. Lembre-se, eu estou usando o Log4NET, mas com aspectos customizados você pode usar qualquer mecanismo de persistência que desejar, o controle fica totalmente em suas mãos.

Eu criei uma classe com o nome “ConsoleLogAspect” e ela irá conter o aspecto customizado que irá interceptar a execução de um método. Veja como ficou o código da classe:

using PostSharp.Aspects;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AOPTutorial
{
    [Serializable]
    public class ConsoleLogAspect : OnMethodBoundaryAspect
    {
        private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        public override void OnEntry(MethodExecutionArgs args)
        {
            log.Debug(string.Format("Executando => {0}.{1}",
                                            args.Method.DeclaringType.Name,
                                            args.Method.Name));
            base.OnEntry(args);
        }

        public override void OnSuccess(MethodExecutionArgs args)
        {
            log.Debug(string.Format("A execução de => {0}.{1} retornou => {2}",
                                            args.Method.DeclaringType.Name,
                                            args.Method.Name,
                                            args.ReturnValue.ToString()));

            base.OnSuccess(args);
        }

        public override void OnExit(MethodExecutionArgs args)
        {
            log.Debug(string.Format("Saindo da execução => {0}.{1}",
                                            args.Method.DeclaringType.Name,
                                            args.Method.Name));
            base.OnExit(args);
        }
    }
}

Agora basta decorar qualquer método com o aspecto “ConsoleLogAspect”. Veja como ficou meu método “Somar” com o novo aspecto que eu criei:

[ConsoleLogAspect]
public static int Somar(int valorA, int valorB)
{
     return valorA + valorB;
}

Ao executar o programa, o arquivo .TXT do log recebe as seguintes novas linhas:

DEBUG 2015-08-21 11:30:58 – Executando => Program.Somar
DEBUG 2015-08-21 11:30:58 – A execução de => Program.Somar retornou => 4
DEBUG 2015-08-21 11:30:58 – Saindo da execução => Program.Somar

Eu usei o aspecto “OnMethodBoundaryAspect” para o exemplo acima, mas existe uma gama de opções disponibilizadas pelo PostSharp como “OnExceptionAspect”, “EventInterceptionAspect” e vários outros aspectos que você pode encontrar no seguinte link:

http://doc.postsharp.net/simple-aspects

Conclusão

Assim como qualquer outro recurso de programação, devemos tomar cuidado ao criar aspectos e espalharmos estes em nossos projetos. Não devemos construir regras de negócio em cima de aspectos, pois isto é uma má prática, uma vez que os aspectos foram criados para abstrair os Cross-Cutting Concerns do código de domínio, e não para abstrair as regras de negócio referentes ao domínio. Devemos focar em construir aspectos para solucionar problemas de infraestrutura que existem ao longo de diversas aplicações e que possam ser reaproveitáveis, sendo assim, modulares.

Espero ter exemplificado bem o que é AOP e como/quando utilizá-la, e que a partir de agora, se necessário, você possa implementar aspectos em seus projetos com sucesso.

Mais informações sobre o PostSharp podem ser encontradas no seguinte link:

http://doc.postsharp.net/conceptual-documentation

Um grande abraço a todos e até a próxima!

Desenvolvedor .NET há mais de 5 anos, apaixonado por Arquitetura e Desenvolvimento de Software.

Atuo hoje como Senior Software Developer em [email protected] Zelândia, mas ao longo da minha carreira profissional trabalhei como Analista de Sistemas e Desenvolvedor em algumas empresas brasileiras e em vários projetos de Software!

Microsoft Certified Professional
MS: Programming in HTML5 with JavaScript and CSS3
MCTS: Web Applications Development with Microsoft .NET Framework 4

Website: http://rafaelpc.com/
LinkedIn: https://br.linkedin.com/in/rafaelpaschoal

Comentários

comentarios