Arquivo para a categoria ‘.net’

Serialização de objetos em JSON com .NET

Quarta-feira, 28 de outubro de 2009 por Fernando Hamasaki de Amorim

Serializar e deserializar instâncias de objetos no formato JSON com .NET acaba sendo muito simples.

Vamos utilizar como exemplo a classe abaixo:

public class SomeFakeClass
{
    public int ID { get; set; }
    public string Text { get; set; }
    public decimal Value { get; set; }
}

E criamos uma instância dela:

SomeFakeClass fake = new SomeFakeClass
{
    ID = 123,
    Text = "I am a sample text.",
    Value = 150.85M
};

Então queremos serializar a variável fake em JSON para obter o seguinte resultado:

{"ID":123,"Text":"I am a sample text.","Value":150.85}

A classe DataContractJsonSerializer torna essa tarefa muito fácil. Basta escrever os dados serializados para um Stream usando o método WriteObject e depois recuperar uma string a partir desse Stream:

MemoryStream stream = new MemoryStream();
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(SomeFakeClass));
serializer.WriteObject(stream, obj);
string json = return Encoding.Default.GetString(stream.ToArray());

Para fazer o inverso, transformar dados em JSON para um objeto, usamos o método ReadObject passando o Stream que possui os dados serializados:

string json = "{"ID":123,"Text":"I am a sample text.","Value":150.85}";
MemoryStream stream = new MemoryStream(json);
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(SomeFakeClass));
SomeFakeClass fake = (SomeFakeClass)serializer.ReadObject(stream);

Um detalhe importante é que a partir do .NET Framework 3.5 Service Pack 1 não há mais a necessidade de decorar a classe que queremos serializar com os atributos DataContract e DataMember, como o exemplo abaixo:

[DataContract]
public class SomeFakeClass
{
    [DataMember]
    public int ID { get; set; }

    [DataMember]
    public string Text { get; set; }

    [DataMember]
    public decimal Value { get; set; }
}

Isso somente se faz necessário se quisermos ter uma controle maior do que será serializado, como por exemplo, serializar uma propriedade com um nome diferente. Na classe abaixo, a propriedade Text é configurada para ser serializada com o nome Message:

[DataContract]
public class SomeFakeClass
{
    [DataMember]
    public int ID { get; set; }

    [DataMember(Name = "Message")]
    public string Text { get; set; }

    [DataMember]
    public decimal Value { get; set; }
}

Os dados serializados em JSON podem ser algo como:

{"ID":123,"Message":"I am a sample text.","Value":150.85}

Para usar a classe DataContractJsonSerializer, que está no namespace System.Runtime.Serialization.Json, é necessário adicionar referências para dois assemblies no seu projeto:

  • System.Runtime.Serialization
  • System.ServiceModel.Web

Agora que já sabemos como serializar e deserializar em JSON, podemos criar um utilitário que faz esse trabalho. O exemplo abaixo utiliza Extensions Methods combinados com Generics:

public static class JsonSerializerExtensions
{
    public static string ToJson<T>(this T obj)
    {
        MemoryStream stream;

        using (stream = new MemoryStream())
        {
            DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
            serializer.WriteObject(stream, obj);
        }

        return Encoding.Default.GetString(stream.ToArray());
    }

    public static T FromJson<T>(this string json)
    {
        T obj;

        using (MemoryStream stream = new MemoryStream(Encoding.Default.GetBytes(json)))
        {
            DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
            obj = (T)serializer.ReadObject(stream);
        }

        return obj;
    }
}

E um exemplo de sua utilização:

SomeFakeClass fake = new SomeFakeClass
{
    ID = 123,
    Text = "I am a sample text.",
    Value = 150.85M
};

string fakeJson = fake.ToJson();
SomeFakeClass otherFake = fakeJson.FromJson<SomeFakeClass>();

.
O código-fonte desse utilitário você pode baixar aqui.


Post original:
http://prodis.pro.br/2009/10/23/serializacao-de-objetos-em-json-com-net

.

Automatizando seus builds com NAnt

Sexta-feira, 16 de outubro de 2009 por Ricardo Tealdi

NAnt (http://nant.sourceforge.net/) é uma ferramenta open source de criação de builds automáticos para .NET, modelado a partir do Ant do Java.

Com o NAnt você consegue compilar o seu projeto .NET, rodar testes unitários, configurar a aplicação de acordo com o ambiente (local, integração contínua, produção, etc), realizar o deploy, entre muitas outras coisas. Porém, para utilizar algumas dessas funcionalidades, é necessário um add-on, chamado NAntContrib (http://nantcontrib.sourceforge.net/), que adiciona várias outras funcionalidades ao NAnt, como por exemplo controle de serviços do Windows, de diretórios virtuais no IIS, utilização do MSBuild, entre outras coisas.

O NAnt funciona através de linha de comando, baseado num XML que você cria para seu build.

Como o foco deste post não é explicar como o NAnt funciona e sim mostrar alguns exemplos de como automatizar seus builds, vamos partir para a codificação.

Criando o primeiro build com o NAnt

Vamos começar com um exemplo simples. Iremos criar um build que apenas compila uma solution, em modo release, que contenha um projeto do tipo Class Library:

  1. Criar uma nova solution no Visual Studio com um projeto do tipo Class Library
  2. Criar um arquivo com o nome de “default.build”, no diretório raiz da solution criada (Ex.: C:\NomeDoProjeto\default.build), com o seguinte conteúdo:
    <?xml version="1.0"?>
    <project name="NAnt Example" default="build">
      <property name="nant.contrib.path" value="C:\Program Files (x86)\nant-contrib\bin" />
      <target name="build">
        <loadtasks assembly="${nant.contrib.path}\NAnt.Contrib.Tasks.dll" />
        <msbuild project="NAnt.sln" target="Rebuild">
          <arg line="/p:Configuration=Release" />
        </msbuild>
      </target>
    </project>
  3. Executar, através de linha de comando, dentro do diretório do projeto, o comando “nant” para realizar o build
    image01-nant-first-execution
  4. Caso tudo dê certo, no final da execução, aparecerá a mensagem “BUILD SUCCEEDED” para confirmar que tudo deu certo
    image02-nant-succeeded

O que fizemos?

  • Linha 2 – Criamos uma tag para o projeto (project), onde definimos o nome do projeto (atributo name) e o target padrão para execução (atributo default), para o NAnt. No nosso caso, definimos nosso target padrão como build, assim não há necessidade de executarmos esse projeto utilizando o comando “nant build“.
  • Linha 3 – Criamos a tag property para definir um valor para uma propriedade, para utilizarmos em outros pontos do nosso arquivo de build. Neste caso criamos uma propriedade com o nome de “nant.contrib.path” com o valor “C:\Program Files (x86)\nant-contrib\bin” para guardarmos o diretório onde foi instalado o NAnt-contrib (É aconselhável que todos os ambientes que você trabalhe esteja instalado no mesmo diretório).
  • Linha 4 – Criamos uma tag para realizar uma tarefa específica, no nosso caso, uma chamada de build (atributo name). Dentro desta tag iremos codificar o que queremos que esta tarefa faça.
  • Linha 5 – Dentro da tarefa build, criamos uma tag para carregar as funcionalidades do NAnt-contrib, lembrando que utilizamos a propriedade “nant.config.path“, que definimos na linha 3. Sempre que quisermos utilizar uma propriedade, devemos utilizar a sintaxe ${nomedapropriedade}.
  • Linha 6 – Agora, vamos utilizar uma task do NAnt-contrib (msbuild), que utilizará o MSBuild para compilar o projeto. Definimos o nome da solução/projeto a ser compilada (atributo project) e o tipo de compilação (atributo target).
  • Linha 7 – Definimos um parâmetro para ser executado no MSBuild (tag arg), no nosso caso, estamos dizendo ao MSBuild que utilize a configuração de Release do projeto (atributo line).

Acabamos de criar nosso primeiro build no NAnt que compila uma solution.

Adicionando execução de testes ao build

Agora, vamos criar um projeto de testes em nossa solution e vamos adicionar uma tarefa ao NAnt para rodar os testes:

  1. Adicionar um projeto de teste a solution
  2. Criar apenas um teste unitário em branco
  3. Modificar o arquivo default.build (Como o arquivo cresceu um pouco, coloquei umas quebras de linhas extras para melhor visualização do código)
    <?xml version="1.0"?>
    <project name="NAnt Example" default="build">
    
      <property name="program.files.path" value="${environment::get-variable('PROGRAMFILES')}" />
      <property name="nant.contrib.path" value="${program.files.path}\nant-contrib\bin" />
      <property name="mstest.path" value="${program.files.path}\Microsoft Visual Studio 9.0\Common7\IDE\MSTest.exe" />
      <property name="test.container.path" value="Tests\bin\Release\NAnt.Tests.dll" />
      <property name="test.results.path" value="TestResults" />
    
      <target name="clean">
        <delete dir="${test.results.path}" />
      </target>
    
      <target name="build" depends="clean">
        <loadtasks assembly="${nant.contrib.path}\NAnt.Contrib.Tasks.dll" />
        <msbuild project="NAnt.sln" target="Rebuild">
          <arg line="/p:Configuration=Release" />
        </msbuild>
    	<call target="test" />
      </target>
    
      <target name="test">
        <mkdir dir="${test.results.path}" failonerror="true" />
        <exec
          program="${mstest.path}"
          commandline=" /testcontainer:${test.container.path} /resultsfile:${test.results.path}\TestResults.trx  /detail:errormessage" />
      </target>
    
    </project>
  4. Executar novamente o comando “nant” para realizar o build
    image03-nant-with-tests

O que fizemos?

  • Linha 4 – Propriedade para pegar o valor da variável de ambiente PROGRAMFILES do Windows
  • Linha 5 – Utilizando a propriedade “program.files.path” para o diretório do NAntContrib
  • Linha 6 – Propriedade com o caminho físico do MSTest (caso use o NUnit, o NAntContrib tem uma tag específica para ele)
  • Linha 7 – Propriedade do caminho físico do arquivo de testes que será executado
  • Linha 8 – Propriedade do diretório onde serão salvos os resultados dos testes
  • Linha 10 – Tarefa para limpar o ambiente antes de começar o build
  • Linha 11 – Apagando o diretório dos resultados dos testes
  • Linha 14 – Adicionado a dependência à tarefa “clean” (atributo depends)
  • Linha 19 – Tag para chamar a tarefa de testes, após compilar o projeto
  • Linha 22 – Tarefa da execução dos testes
  • Linha 23 – Criando o diretório para o resultado dos testes. Caso não seja possível criar o diretório, o build para por aqui
  • Linha 24 a 26 – Chamando o MSTest para executar os testes e salvar os resultados

Agora nosso build só será compilado quando todos os testes da solution estiverem passando.

Limpando a sujeira

Com o crescimento e refatoração de nossos projetos, normalmente criamos arquivos novos e apagamos arquivos desnecessários, com isso, os diretórios onde são gerados os assemblies dos projetos, vão armazenando arquivos antigos, que provavelmente não serão mais necessários. Então vamos criar um build para apagarmos todos os arquivos das pastas obj e bin que o MSBuild cria ao compilar os projetos:

  1. Alterar o arquivo default.build
    <?xml version="1.0"?>
    <project name="NAnt Example" default="build">
    
      <property name="program.files.path" value="${environment::get-variable('PROGRAMFILES')}" />
      <property name="nant.contrib.path" value="${program.files.path}\nant-contrib\bin" />
      <property name="mstest.path" value="${program.files.path}\Microsoft Visual Studio 9.0\Common7\IDE\MSTest.exe" />
      <property name="test.container.path" value="Tests\bin\Release\NAnt.Tests.dll" />
      <property name="test.results.path" value="TestResults" />
    
      <target name="clean">
        <delete>
          <fileset>
            <include name="**\bin\**" />
    		<include name="**\obj\**" />
          </fileset>
        </delete>
        <delete dir="${test.results.path}" />
      </target>
    
      <target name="test">
        <mkdir dir="${test.results.path}" failonerror="true" />
        <exec
          program="${mstest.path}"
          commandline=" /testcontainer:${test.container.path} /resultsfile:${test.results.path}\TestResults.trx /detail:errormessage" />
      </target>
    
      <target name="build" depends="clean">
        <loadtasks assembly="${nant.contrib.path}\NAnt.Contrib.Tasks.dll" />
        <msbuild project="NAnt.sln" target="Rebuild">
          <arg line="/p:Configuration=Release" />
        </msbuild>
        <call target="test" />
      </target>
    
    </project>
  2. Executar o nant
    image04-nant-clean

O que fizemos?

  • Linha 11 a 16 – Adicionando a tag delete para apagar todos os arquivos, de todas as pastas bin e obj, existentes na solution

Agora não teremos mais problemas com arquivos antigos do projeto.

Diferentes arquivos de configuração para cada ambiente

Recapitulando, nós já conseguimos compilar um projeto, rodar os testes e limpar os diretórios das compilações, porém, se precisarmos utilizar arquivos de configuração para nossos projetos, com certeza teremos problemas com as diferentes configurações para cada ambiente (desenvolvimento, integração contínua, homologação, produção). Então, vamos ver um exemplo para utilar os arquivos de configurações corretos, de acordo com o ambiente escolhido para o build:

  1. Alterar o arquivo default.build
    <?xml version="1.0"?>
    <project name="NAnt Example" default="build">
    
      <property name="environment" value="local" />
      <property name="program.files.path" value="${environment::get-variable('PROGRAMFILES')}" />
      <property name="nant.contrib.path" value="${program.files.path}\nant-contrib\bin" />
      <property name="mstest.path" value="${program.files.path}\Microsoft Visual Studio 9.0\Common7\IDE\MSTest.exe" />
      <property name="test.project.path" value="Tests" />
      <property name="test.assembly" value="NAnt.Tests.dll" />
      <property name="test.container.path" value="${test.project.path}\bin\Release\${test.assembly}" />
      <property name="test.results.path" value="TestResults" />
    
      <target description="Configures" name="config">
        <property name="build.config.file" value="config.${environment}.xml" dynamic="true" />
        <if test="${file::exists(build.config.file)}">
          <echo message="Loading ${build.config.file}" />
          <include buildfile="${build.config.file}" verbose="true" />
        </if>
        <if test="${not file::exists(build.config.file) and environment != 'local'}">
          <fail message="Configuration file '${build.config.file}' could not be found." />
        </if>
      </target>
    
      <target name="clean">
        <delete>
          <fileset>
            <include name="**\bin\**" />
            <include name="**\obj\**" />
          </fileset>
        </delete>
        <delete dir="${test.results.path}" />
      </target>
    
      <target name="test">
        <mkdir dir="${test.results.path}" failonerror="true" />
        <copy file="${test.project.path}\${test.config.file}" tofile="${test.container.path}.config" failonerror="true" overwrite="true" />
        <exec
          program="${mstest.path}"
          commandline=" /testcontainer:${test.container.path} /resultsfile:${test.results.path}\TestResults.trx /detail:errormessage" />
      </target>
    
      <target name="build_ci">
        <property name="environment" value="ci" />
        <call target="build"/>
      </target>
    
      <target name="build" depends="config clean">
        <loadtasks assembly="${nant.contrib.path}\NAnt.Contrib.Tasks.dll" />
        <msbuild project="NAnt.sln" target="Rebuild">
          <arg line="/p:Configuration=Release" />
        </msbuild>
        <call target="test" />
      </target>
    
    </project>
  2. Criar dois arquivos de configuração para o projeto de teste, um chamado App.config e outro ci.App.Config (local e integração contínua), para simularmos os arquivos dos dois ambientes
  3. Criar um arquivo chamado config.local.xml no mesmo diretório do arquivo default.build (na raiz da solution)
    <project>
    	<property name="test.config.file" value="ci.App.config" />
    </project>
  4. Criar um arquivo chamado config.ci.xml no mesmo diretório do arquivo default.build (na raiz da solution)
    <project>
    	<property name="test.config.file" value="App.config" />
    </project>
  5. Executar o comando “nant build_ci

O que fizemos?

  • Linha 4 – Propriedade para definir o ambiente
  • Linha 8 – Propriedade com o diretório do projeto de testes
  • Linha 9 – Propriedade com o nome do arquivo do teste
  • Linha 14 a 22 – Tarefa para verificar se existe o arquivo de configuração a ser carregado, baseado na propriedade “environment
  • Linha 36 – Copiando o arquivo de configuração do teste, baseado na propriedade “test.config.file“, que é carregada no arquivo de configuração de cada ambiente (config.local.xml ou config.ci.xml). Caso seja um build local (nant build), irá sobrescrever o arquivo de configuração com o arquivo “App.config“, caso seja um build para integração contínua (nant build_ci), irá sobrescrever o arquivo “ci.App.config“.
  • Linha 42 a 45 – Tarefa para realizar o build para o ambiente de integração contínua.
  • Linha 47 – Adicionado a dependência da tarefa “config” antes de realizar o build

Agora nosso build pode ter arquivos de configurações diferentes para cada ambiente.

Criando um pacote para deploy

Normalmente, nós desenvolvedores, não temos acesso direto aos servidores de produção para realizar o deploy. Com isso, em alguns casos, temos que criar um pacote dos assemblies de uma aplicação e enviar para a equipe responsável que irá efetuar o deploy. Então, neste exemplo, vamos criar este pacote, com todos os arquivos necessários de configurações, específicos para o ambiente de produção:

  1. Alterar o arquivo default.build
    <?xml version="1.0"?>
    <project name="NAnt Example" default="build">
    
      <property name="environment" value="local" />
      <property name="program.files.path" value="${environment::get-variable('PROGRAMFILES')}" />
      <property name="nant.contrib.path" value="${program.files.path}\nant-contrib\bin" />
      <property name="mstest.path" value="${program.files.path}\Microsoft Visual Studio 9.0\Common7\IDE\MSTest.exe" />
      <property name="project.path" value="NAnt.Core" />
      <property name="project.binary.path" value="${project.path}\bin\Release" />
      <property name="project.assembly" value="NAnt.Core.dll" />
      <property name="test.project.path" value="Tests" />
      <property name="test.assembly" value="NAnt.Tests.dll" />
      <property name="test.container.path" value="${test.project.path}\bin\Release\${test.assembly}" />
      <property name="test.results.path" value="TestResults" />
      <property name="deploy.package.path" value="DeployPackage" />
      <property name="temp.path" value="Temp" />
    
      <target description="Configures" name="config">
        <property name="build.config.file" value="config.${environment}.xml" dynamic="true" />
        <if test="${file::exists(build.config.file)}">
          <echo message="Loading ${build.config.file}" />
          <include buildfile="${build.config.file}" verbose="true" />
        </if>
        <if test="${not file::exists(build.config.file) and environment != 'local'}">
          <fail message="Configuration file '${build.config.file}' could not be found." />
        </if>
      </target>
    
      <target name="clean">
        <delete>
          <fileset>
            <include name="**\bin\**" />
            <include name="**\obj\**" />
          </fileset>
        </delete>
        <delete dir="${test.results.path}" />
        <delete dir="${temp.path}" />
        <delete dir="${deploy.package.path}" />
      </target>
    
      <target name="test">
        <mkdir dir="${test.results.path}" failonerror="true" />
        <copy file="${test.project.path}\${test.config.file}" tofile="${test.container.path}.config" failonerror="true" overwrite="true" />
        <exec
          program="${mstest.path}"
          commandline=" /testcontainer:${test.container.path} /resultsfile:${test.results.path}\TestResults.trx /detail:errormessage" />
      </target>
    
      <target name="build_ci">
        <property name="environment" value="ci" />
        <call target="build"/>
      </target>
    
      <target name="build_production">
        <property name="environment" value="production" />
        <call target="package"/>
      </target>
    
      <target name="build" depends="config clean">
        <loadtasks assembly="${nant.contrib.path}\NAnt.Contrib.Tasks.dll" />
        <msbuild project="NAnt.sln" target="Rebuild">
          <arg line="/p:Configuration=Release" />
        </msbuild>
        <call target="test" />
      </target>
    
      <target name="package" depends="build">
        <mkdir dir="${deploy.package.path}" failonerror="true" />
        <mkdir dir="${temp.path}" failonerror="true" />
    
        <copy todir="${temp.path}" overwrite="true" verbose="true">
          <fileset basedir="${project.binary.path}">
            <include name="*/**" />
            <exclude name="*.pdb" />
            <exclude name="*.config" />
          </fileset>
        </copy>
    
        <copy file="${project.path}\${project.config.file}" tofile="${temp.path}\${project.assembly}.config" />
    
        <copy todir="${deploy.package.path}" overwrite="true">
          <fileset basedir="${temp.path}">
            <include name="*/**" />
          </fileset>
        </copy>
    
        <delete dir="${temp.path}" />
      </target>
    
    </project>
  2. Criar dois arquivos de configuração para o projeto principal, um chamado App.config e outro production.App.Config (local e produção)
  3. Criar um arquivo chamado config.production.xml no mesmo diretório do arquivo default.build (na raiz da solution)
    <project>
    	<property name="test.config.file" value="ci.App.config" />
    	<property name="project.config.file" value="production.App.config" />
    </project>
  4. Executar o comando nant “build_production

O que fizemos?

  • Linha 8 a 10 – Propriedades com os dados do diretório e assembly do projeto principal, que será feito o deploy
  • Linha 15 – Propriedade com o diretório que será criado, onde ficará o pacote para deploy
  • Linha 16 – Propriedade com o diretório temporário, onde organizaremos os arquivos gerados da compilação, antes de enviar para o diretório do pacote
  • Linha 37 e 38 – Apagando os diretórios gerados (deploy e temporário)
  • Linha 54 a 57 – Tarefa para gerar o pacote para deploy
  • Linha 68 – Criando o diretório do pacote para deploy
  • Linha 69 – Criando o diretório temporário
  • Linha 71 a 77 – Copiando todos os arquivos do diretório onde foi compilado o projeto, para o diretório temporário, exceto os arquivos com extensão “pdb” e “config
  • Linha 79 – Copiando o arquivo de configuração para o ambiente de produção (carregado da propriedade “project.config.file” do arquivo “config.production.xml“)
  • Linha 81 a 88 – Copiando os arquivos do diretório temporário para o diretório onde ficará o pacote para deploy
  • Linha 87 – Apagando o diretório temporário

Pronto, agora você terá um diretório chamado “DeployPackage” com seu pacote prontinho para ser enviado para a equipe responsável no deploy da aplicação.

Existem inúmeras outras funcionalidades para automatização de seus builds com o NAnt e o NAntContrib, porém, creio que com esses exemplos, voces consigam ter uma idéia de como criar builds automatizados para seus projetos .NET, mas é claro que, para cada projeto, você vai precisar ajeitar seu build conforme a necessidade.

Referências

Leitura recomendada

Utilizando aspectos em C# com PostSharp

Sábado, 5 de setembro de 2009 por Mozair aka MACSkeptic

Um pouco sobre programação orientada a aspectos (AOP)

Ao longo dos últimos anos, a medida em que o hardware foi se tornando um recurso cada vez mais barato e poderoso, o foco das linguagens de programação tem se voltado para clareza ao invés de performance.

Onde antes era necessário, por exemplo, ponderar com muito cuidado qual o melhor algoritmo para iterar uma lista, hoje esta é uma questão secundária. O que isto propicia a nós, desenvolvedores, é a possibilidade de focar nosso tempo e esforço em questões de clareza e manutenibilidade em nossos códigos.

Com estas novas preocupações em mente, surgiu o paradigma orientado a objetos, que visa traduzir da forma mais natural possível as entidades reais de nosso negócio, para classes e instâncias em nosso código.

Porém, um grande problema que aparece quando se desenvolve um software orientado a objetos é o espalhamento de responsabilidades em comum ao longo de várias classes. Alguns exemplos clássicos deste problema são:

  • Log;
  • Autenticação;
  • Abrir/Fechar conexões;
  • Tratamentos de exceção;

Estas preocupações normalmente encontram-se espalhadas ao longo do código de diversas classes, mesmo que o comportamento desejado seja exatamente igual em todas elas.

Para abordar este problema de espalhamento, surgiu o paradigma de programação orientada a aspectos. Este visa complementar a programação orientada a objetos, eliminando em grande parte o espalhamento de código para preocupações comuns em diversos pontos do código. A seguir, tentarei mostrar, utilizando um exemplo prático, as vantagens que o uso de aspectos podem trazer para a clareza do código desenvolvido.

Aprendendo por meio de exemplos

O problema imediato que o espalhamento de código similar gera é: para cada modificação que seja necessária neste código espalhado, será necessário modificá-lo manualmente em cada ponto – como nós, desenvolvedores, sabemos, tarefas manuais como esta estão fadadas a gerar erros ou inconsistências.

A seguir, implementaremos uma classe de conta corrente, que possibilitará depósitos e saques, começando, naturalmente, pelos testes:

[TestMethod]
public void WithdrawShouldDecreaseBalance()
{
    Account account1 = AccountBuilder.New
        .BelongingTo("MACSkeptic")
        .WithInitialBalance(200.95M)
        .IdentifiedBy(773)
        .Instance;

    Assert.AreEqual(100.95M, account1.Withdraw(100).CurrentBalance);
    Assert.AreEqual(0.0M, account1.Withdraw(100.95M).CurrentBalance);
    Assert.AreEqual(-10.0M, account1.Withdraw(10.00M).CurrentBalance);
}

[TestMethod]
public void DepositShouldIncreaseBalance()
{
    Account account1 = AccountBuilder.New
        .BelongingTo("MACSkeptic")
        .WithInitialBalance(-50.42M)
        .IdentifiedBy(666)
        .Instance;

    Assert.AreEqual(-0.42M, account1.Deposit(50).CurrentBalance);
    Assert.AreEqual(79.58M, account1.Deposit(80).CurrentBalance);
}

Para atender ao comportamento descrito acima, implementaremos a classe “Account”, denotada a seguir:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Codevil.MACSkeptic.PostSharpExample.Entities
{
    public class Account
    {
        public long Number { get; set; }
        public string Owner { get; set; }
        public decimal CurrentBalance { get { return this.currentBalance; } }

        private decimal currentBalance;

        public Account(long number, string owner)
            : this(number, owner, 0)
        {
        }

        public Account(long number, string owner, decimal initialBalance)
        {
            this.Number = number;
            this.Owner = owner;
            this.currentBalance = initialBalance;
        }

        public Account Deposit(decimal howMuch)
        {
            Console.WriteLine(string.Format(
                "New deposit transaction on account {0}.
                                       Balance before operation is ${1}.",
                this.Number,
                this.CurrentBalance));

            Console.WriteLine(string.Format(
                "Depositing ${0} on account {1}.", howMuch, this.Number));

            this.currentBalance += howMuch;

            Console.WriteLine(string.Format(
                "Finished deposit transaction on account {0}.
                                       Balance after the operation is ${1}.",
                this.Number,
                this.CurrentBalance));

            return this;
        }

        public Account Withdraw(decimal howMuch)
        {
            Console.WriteLine(string.Format(
                "New withdraw transaction on account {0}.
                                      Balance before operation is ${1}.",
                this.Number,
                this.CurrentBalance));

            Console.WriteLine(string.Format(
                "Withdrawing ${0} on account {1}.", howMuch, this.Number));

            this.currentBalance -= howMuch;

            Console.WriteLine(string.Format(
                "Finished withdraw transaction on account {0}.
                                   Balance after the operation is ${1}.",
                this.Number,
                this.CurrentBalance));

            return this;
        }
    }
}

Como pode ser visto, nossa conta bancária tem basicamente dois métodos, responsáveis por depositar (Deposit) e sacar (Withdraw) dinheiro. Por enquanto ainda não há tratamento de saldo nas saques, caso se tire mais dinheiro do que o disponível, o resultado será uma conta com saldo negativo.

Logo já conseguimos notar que o log (sendo realizado no próprio console, para manter o foco no que realmente interessa neste artigo) de operaçòes de depósito e saque é bem parecido, gerando um código claramente repetitivo.

Uma possível refatoração nos possibilita eliminar um pouco de repetição, fazendo uso da refatoração “extrair método”, temos:

public Account Deposit(decimal howMuch)
{
    this.LogTransactionStarting("deposit");
    this.LogTransactionDetails("Depositing", howMuch);
    this.currentBalance += howMuch;
    this.LogTransactionFinished("deposit");
    return this;
}
public Account Withdraw(decimal howMuch)
{
    this.LogTransactionStarting("withdraw");
    this.LogTransactionDetails("Withdrawing", howMuch);
    this.currentBalance -= howMuch;
    this.LogTransactionFinished("withdraw");
    return this;
}
private void LogTransactionStarting(string action)
{
    Console.WriteLine(string.Format(
        "New {2} transaction on account {0}.
                                 Balance before operation is ${1}.",
        this.Number,
        this.CurrentBalance,
        action));
}
private void LogTransactionDetails(string action, decimal howMuch)
{
    Console.WriteLine(string.Format(
        "{2} ${0} on account {1}.", howMuch, this.Number, action));
}
private void LogTransactionFinished(string action)
{
    Console.WriteLine(string.Format(
        "Finished {2} transaction on account {0}.
                                 Balance after the operation is ${1}.",
        this.Number,
        this.CurrentBalance,
        action));
}

O código já ficou mais limpo e com menos repetições. Porém, os métodos de “Deposit” e “Withdraw”, e mais especificamente a classe “Account” não deveríam estar preocupados em logar as ações. Usando apenas conceitos de orientação a objetos, o máximo que conseguiríamos fazer para melhorar o código acima seria mover os métodos de log para outra classe. Esta ação melhoraria nosso código, mas ainda assim teríamos as chamadas aos métodos de log na classe “Account”, tirando o foco no negócio, tanto durante a codificação, quanto quando se venha a ler o código no futuro.

Há uma conhecida frase sobre classes em orientação a objetos que diz que se você precisa utilizar “e” ao definir o que sua classe faz, provavelmente ela está aglomerando muitas responsabilidades. No caso, nossa classe de conta faz transações e gera logs de transações.

Neste ponto, podemos notar a natureza do log que precisamos. Temos:

  • Um evento de log no início dos métodos de depósito e saque;
  • Um evento de log com detalhes específicos sobre o depósito e saque sendo realizado no momento;
  • Um evento de log ao térmido dos métodos de depósito e saque.

Uma ferramenta bastante competente em auxiliar no uso de aspectos em .NET é o PostSharp, cujo slogan, “make sense, not code” (faça sentido, não faça código), diz bastante sobre a idéia central  sobre a qual se sedimenta o paradigma de aspectos. Para a sequência deste artigo será necessário o download do PostSharp (utilizaremos a versão 1.5), que pode ser realizado clicando aqui (é necessário registrar-se no site da ferramenta. O registro é gratuito e pode ser feito aqui).

Após fazer a instalação do PostSharp, devemos adicionar as referências às bibliotecas PostSharp.Laos e PostSharp.Public em nosso projeto, conforme imagem a seguir:

image

A documentação detalhada do PostSharp (em inglês) pode ser conferida clicando-se aqui.

Para nossa classe “Account” iremos utilizar dois aspectos:

  • OnMethodBoundaryAspect (ao redor do método): define pontos de entrada ao redor das chamadas de um método. Isto é, imediatamente antes e imediatamente depois de sua chamada. Este aspecto é ideal para o log antes e depois de uma transação em nossa classe “Account”;
  • OnMethodInvocationAspect (na chamada do método): define um ponto de entrada assim que um método é chamado, incluindo detalhes como os parâmetros informados nessa chamada específica. Este aspecto é ideal para o log de detalhes de transação em nossa classe “Account”.

Primeiramente, vamos ver como fica a implementação do aspecto “ao redor” na prática:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PostSharp.Laos;
using Codevil.MACSkeptic.PostSharpExample.Entities;

namespace Codevil.MACSkeptic.PostSharpExample.Aspects
{
    [Serializable]
    public class LogAccountStatusBeforeAndAfterTransaction :
                                            OnMethodBoundaryAspect
    {
        public override void OnEntry(MethodExecutionEventArgs eventArgs)
        {
            Account account = (Account)eventArgs.Instance;
            Console.WriteLine(string.Format(
                "New {2} transaction on account {0}.
                                    Balance before operation is ${1}.",
                account.Number,
                account.CurrentBalance,
                eventArgs.Method.Name));
        }
        public override void OnExit(MethodExecutionEventArgs eventArgs)
        {
            Account account = (Account)eventArgs.Instance;
            Console.WriteLine(string.Format(
               "Finished {2} transaction on account {0}.
                                   Balance after the operation is ${1}.",
               account.Number,
               account.CurrentBalance,
               eventArgs.Method.Name));
        }
    }
}

O aspecto “OnMethodBoundary” possibilita a implementação dos métodos “OnEntry” (antes do método) e “OnExit” (após o método). No código acima pode-se reparar que nosso aspecto precisa de um parâmetro especificando qual a ação está sendo tomada e o código para log foi copiado diretamente do que tínhamos antes na classe “Account”. Um detalhe importante é que todas as classes que implementam algum aspecto do PostSharp devem ser serializáveis.

Vamos ver agora como fica o código de nossa classes “Account” fazendo uso deste aspecto:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Codevil.MACSkeptic.PostSharpExample.Aspects;

namespace Codevil.MACSkeptic.PostSharpExample.Entities
{
    public class Account
    {
        public long Number { get; set; }
        public string Owner { get; set; }
        public decimal CurrentBalance { get { return this.currentBalance; } }
        private decimal currentBalance;

        public Account(long number, string owner)
            : this(number, owner, 0)
        {
        }

        public Account(long number, string owner, decimal initialBalance)
        {
            this.Number = number;
            this.Owner = owner;
            this.currentBalance = initialBalance;
        }
        [LogAccountStatusBeforeAndAfterTransaction]
        public Account Deposit(decimal howMuch)
        {
            this.LogTransactionDetails("Depositing", howMuch);
            this.currentBalance += howMuch;
            return this;
        }
        [LogAccountStatusBeforeAndAfterTransaction]
        public Account Withdraw(decimal howMuch)
        {
            this.LogTransactionDetails("Withdrawing", howMuch);
            this.currentBalance -= howMuch;
            return this;
        }
        private void LogTransactionDetails(string action, decimal howMuch)
        {
            Console.WriteLine(string.Format(
                "{2} ${0} on account {1}.", howMuch, this.Number, action));
        }
    }
}

Podemos perceber os atributos adicionados nas linhas 27 e 34, que apenas informam um aspecto sobre o comportamento deste método, cuja implementação não interessa para a classe “Account”.

Agora, vamos criar um aspecto “OnMethodInvocation”, para o log de detalhes de transação:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PostSharp.Laos;
using Codevil.MACSkeptic.PostSharpExample.Entities;

namespace Codevil.MACSkeptic.PostSharpExample.Aspects
{
    [Serializable]
    public class LogAccountTransactionDetails : OnMethodInvocationAspect
    {
        public override void OnInvocation(MethodInvocationEventArgs eventArgs)
        {
            Account account = (Account)eventArgs.Instance;
            Console.WriteLine(string.Format(
                "{2} ${0} on account {1}.",
                eventArgs.GetArgumentArray().First(),
                account.Number,
                eventArgs.Method.Name));
            eventArgs.Proceed();
        }
    }
}

Novamente, apenas movemos a implementação do método original de log que estava em nossa classe “Account” para dentro de nosso aspecto. O parâmetro “eventArgs” provê acesso, entre outras coisas:

  • À instância corrente da classe na qual o aspecto está sendo aplicado;
  • Ao método sendo chamado;
  • Aos parâmetros passados na chamada do método.

Um ponto importante a se notar no método acima é a chamada “eventArgs.Proceed” (proceder). Este comando diz ao weaver que o método original deve ser executado neste momento, ou seja, o fluxo original do método deve proceder sem alterações. Caso necessário, poderíamos, por exemplo: :

  • Modificar os parâmetros que estão sendo passados para o método original (basta passar o novo parâmetro para o método “proceed”);
  • Sequer chamar o método original neste ponto (basta omitir a chamada ao método “proceed”).

Com isso, conseguimos mover toda nossa preocupação com o log para os aspectos. Nossa classe “Account” atualizada fica assim:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Codevil.MACSkeptic.PostSharpExample.Aspects;

namespace Codevil.MACSkeptic.PostSharpExample.Entities
{
    public class Account
    {
        public long Number { get; set; }
        public string Owner { get; set; }
        public decimal CurrentBalance { get { return this.currentBalance; } }
        private decimal currentBalance;

        public Account(long number, string owner)
            : this(number, owner, 0)
        {
        }

        public Account(long number, string owner, decimal initialBalance)
        {
            this.Number = number;
            this.Owner = owner;
            this.currentBalance = initialBalance;
        }
        [LogAccountStatusBeforeAndAfterTransaction]
        [LogAccountTransactionDetails]
        public Account Deposit(decimal howMuch)
        {
            this.currentBalance += howMuch;
            return this;
        }
        [LogAccountStatusBeforeAndAfterTransaction]
        [LogAccountTransactionDetails]
        public Account Withdraw(decimal howMuch)
        {
            this.currentBalance -= howMuch;
            return this;
        }
    }
}

Antes de mais nada, utilizando uma expressão regular, podemos deixar nosso código ainda mais limpo:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Codevil.MACSkeptic.PostSharpExample.Aspects;

namespace Codevil.MACSkeptic.PostSharpExample.Entities
{
    [LogAccountStatusBeforeAndAfterTransaction(
		AttributeTargetMembers = "regex:(Deposit)|(Withdraw)")]
    [LogAccountTransactionDetails(
		AttributeTargetMembers = "regex:(Deposit)|(Withdraw)")]
    public class Account
    {
        public long Number { get; set; }
        public string Owner { get; set; }
        public decimal CurrentBalance { get { return this.currentBalance; } }
        private decimal currentBalance;

        public Account(long number, string owner)
            : this(number, owner, 0)
        {
        }

        public Account(long number, string owner, decimal initialBalance)
        {
            this.Number = number;
            this.Owner = owner;
            this.currentBalance = initialBalance;
        }
        public Account Deposit(decimal howMuch)
        {
            this.currentBalance += howMuch;
            return this;
        }
        public Account Withdraw(decimal howMuch)
        {
            this.currentBalance -= howMuch;
            return this;
        }
    }
}

Repare que agora o código fonte de nossa classe “Account” não está mais poluído com a preocupação de manter um log das transações realizadas.

Quer mais? Ainda podemos fazer uma melhoria final, agora que temos um pouco mais de domínio sobre o funcionamento do PostSharp, podemos eliminar a utilização do aspecto “OnMethodBoundary” utilizado para os logs de início e término da transação. Para isso, basta realizarmos algumas pequenas modificações em nosso aspecto “OnMethodInvocation”, conforme denotado a seguir:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PostSharp.Laos;
using Codevil.MACSkeptic.PostSharpExample.Entities;

namespace Codevil.MACSkeptic.PostSharpExample.Aspects
{
    [Serializable]
    public class LogAccountTransactionDetails : OnMethodInvocationAspect
    {
        public override void OnInvocation(MethodInvocationEventArgs eventArgs)
        {
            Account account = (Account)eventArgs.Instance;

            LogTransactionStarting(eventArgs, account);
            LogTransactionDetails(eventArgs, account);
            eventArgs.Proceed();
            LogTransactionFinished(eventArgs, account);
        }
        private static void LogTransactionDetails(
			MethodInvocationEventArgs eventArgs, Account account)
        {
            Console.WriteLine(string.Format(
                "{2} ${0} on account {1}.",
                eventArgs.GetArgumentArray().First(),
                account.Number,
                eventArgs.Method.Name));
        }
        private static void LogTransactionStarting(
			MethodInvocationEventArgs eventArgs, Account account)
        {
            Console.WriteLine(string.Format(
                "New {2} transaction on account {0}.
                               Balance before operation is ${1}.",
                account.Number,
                account.CurrentBalance,
                eventArgs.Method.Name));
        }
        private static void LogTransactionFinished(
			MethodInvocationEventArgs eventArgs, Account account)
        {
            Console.WriteLine(string.Format(
               "Finished {2} transaction on account {0}.
                                Balance after the operation is ${1}.",
               account.Number,
               account.CurrentBalance,
               eventArgs.Method.Name));
        }
    }
}

Repare que primeiro logamos o início da transação (linha 17), depois os detalhes sobre parâmetros envolvidos na transação (linha 18), só então prosseguimos com a chamada do método original (linha 19), e por último logamos o estado final de nossa conta (linha 20). Com isso obtivemos um comportamento idêntico ao que tínhamos anteriormente com dois aspectos, porém utilizando apenas um. Por fim, basta ajustarmos a classe “Account” para não mais utilizar o aspecto “ao redor”:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Codevil.MACSkeptic.PostSharpExample.Aspects;

namespace Codevil.MACSkeptic.PostSharpExample.Entities
{
    [LogAccountTransactionDetails(
		AttributeTargetMembers = "regex:(Deposit)|(Withdraw)")]
    public class Account
    {
        public long Number { get; set; }
        public string Owner { get; set; }
        public decimal CurrentBalance { get { return this.currentBalance; } }
        private decimal currentBalance;
        private const decimal DefaultInitialBalance = 0;

        public Account(long number, string owner)
            : this(number, owner, DefaultInitialBalance)
        {
        }
        public Account(long number, string owner, decimal initialBalance)
        {
            this.Number = number;
            this.Owner = owner;
            this.currentBalance = initialBalance;
        }

        public Account Deposit(decimal howMuch)
        {
            this.currentBalance += howMuch;
            return this;
        }
        public Account Withdraw(decimal howMuch)
        {
            this.currentBalance -= howMuch;
            return this;
        }
    }
}

Ou seja, mesmo em um pequeno exemplo como este, substituímos pelo menos 6 linhas de código “alien” da classe “Account” original (considerando a melhor implementação possível sem aspectos, onde os métodos de log tivessem sido movidos para outra classe) que estavam relacionadas com a preocupação de manter um log de transações. No lugar delas, adicionamos apenas um atributo declarando um aspecto de comportamento esperado quanto às transações. Ressaltando, para evitar mal entendidos: a vantagem não é necessariamente escrever menos código, mas sim separar claramente as responsabilidades e escrever o código onde ele deve estar.

Fico por aqui, espero que tenham gostado e percebido o quanto aspectos podem facilitar o desenvolvimento e melhorar a manutenibilidade de código. Deixo uma recomendação final para que os interessados em usar aspectos em seus projetos leiam com atenção a documentação do PostSharp (ou de qualquer outra ferramenta que venham a usar) para conferir o que pode ser feito em termos de otimização e detalhes sobre performance (o PostSharp oferece vários recursos de inicialização de aspectos em tempo de compilação, diminuindo o overhead em tempo de execução).

Como sempre, o código base deste artigo está disponível no meu github, e pode ser baixado aqui. Sintam-se à vontade para deixar suas dúvidas, críticas e sugestões nos comentários e até a próxima ;) .

Referências:

Leituras recomendadas:

.Net Architets Day – Boas práticas de arquitetura e engenharia de software

Quarta-feira, 1 de julho de 2009 por Luciano Coelho

dotnetarchitets No último sábado (27/06) rolou o .Net Architets Day 2009 voltado para arquitetura de software (com foco em .Net).

Pouco ou quase nada se falou sobre uso de alguma ferramenta específicas Microsoft, até porque o foco do grupo que já existe há algum tempo é exatamente a utilização do .Net com práticas de engenharia de software e arquitertura.

O evento, segundo a organização, não teve fins lucrativos e o valor foi revertido em brindes e coffe break além de algumas outras despezas (achei muito bacana a prestação de contas apresentada pelo Giovanni, idealizador do grupo).

Estes foram os temas apresentados, com um pequeno resumo de cada palestra. De acordo com a organização, as apresentações e as filmagens estarão disponíveis no site do grupo em breve.

Programando com prazer com Domain Driven Design (DDD)Giovanni Basi

A principal preocupação do arquiteto ou desenvolvedor de software deve ser com o futuro, ou seja, a “manutenibilidade” do sistema. Com o design baseado na lógica do domínio do cliente (DDD), tudo fica mais fácil, desde a forma de se comunicar (linguagem ubíqua) até a modelagem, desenvolvimento e manutenção do software.

Utilizando Injeção de dependência com Unity (Enterprise Library)Leandro Daniel

O acoplamento é um problema enorme em POO. Fazer testes em uma classe de negócio que dependa de uma outra que envia e-mail, por exemplo, ou adicionar uma nova funcionalidade a um pedaço que já esteja amarrado a uma implementação é triste demais. O Unity, um dos blocos da Enterprise Library (incorporado a partir da versão 4.0), foi criado para ajudar nessa tarefa injetando a dependência quando necessário. No entanto, é preciso avaliar o uso para não tornar seu software ainda mais acoplado :)

ASP.Net MVC: tome seu HTML de voltaVictor Cavalcante

Nesta palestra foi feita uma comparação entre o ASP.NET MVC e Web Forms, mostrando como ficamos como, com este último, muito presos à interface e fica difícil fazer testes enquanto que, com MVC separa a lógica da apresentação ficando mais flexível e testável. Por outro lado, MVC tem um preço, é necessário colocar a mão na massa, controlar o HTML, é necessário saber programar para web.

ORM – Sendo preguiçoso com NHibernateJuliano Oliveira

No início da palestra o Juliano trocou o título para “Sendo produtivo com NHibernate”. Este que é um dos frameworks mais conhecidos para mapeamento de objeto relacional é de grande valor na hora de desenvolver seu sistema e diminui bastante a dor de cabeça com criação de tabelas, colunas, constraints, etc. na base de dados. Foi mostrado também o NHProf uma ferramenta comercial para que funciona como o Profiler do SQL Server.

Testes: garantindo que seu código faz o que você querMauricio Aniche

Uma frase que eu tenho ouvido muito ultimamente, mas, graças a Deus, a grande maioria das vezes, só como ilustração “Tá pronto, só falta testar”, foi mencionada mais uma vez. E não é difícil ouvir isso nas empresas que ainda não adotam boas práticas de desenvolvimento. Foi feita uma bela apresentação de como os testes podem ajudar tanto a evitar bugs como na qualidade e na própria codificação, pois fica fácil entender a lógica e as regras de negócio fazendo testes. O uso de ferramentas de automatização de testes como o NUnit ou o Próprio MSTest do Visual Studio, o uso de frameworks de mock potencializam a produtividade.

Valeu muito a pena participar e já estou esperando o próximo.

Como medir o uso da CPU utilizando Performance Counters

Segunda-feira, 4 de maio de 2009 por Fernando Hamasaki de Amorim

Na última semana no trabalho, dois desenvolvedores estavam procurando uma forma de recuperar a porcentagem de uso da CPU utilizando .NET. Eles encontraram uma solução utilizando Win32_Processor de WMI e classes do namesapce System.Management, escrevendo algo mais ou menos assim:

ObjectQuery query = new ObjectQuery("SELECT * FROM Win32_Processor");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);

int load = 0;
int cpus = 0;

foreach (ManagementObject mo in searcher.Get())
{
    load += Convert.ToInt32(mo["LoadPercentage"]);
    numCpus++;
}

decimal cpuUsage = load / cpus;

Uma maneira mais fácil de fazer isso, e que atende ao propósito de medir recursos utilizados da máquina, é utilizar Performance Counters. Classes como PerformanceCounter e PerformanceCounterCategory, que são encontradas no namespace System.Diagnostics, lhe dão acesso não somente a informações do uso do processador, mas também informações sobre cachê de sistema, disco físico, memória, threads, entre outros.

O exemplo abaixo mostra como criar uma instância da classe PerformanceCounter para recuperar a porcentagem do uso da CPU naquele instante:

PerformanceCounter cpuCounter = new PerformanceCounter
{
    CategoryName = "Processor",
    CounterName = "% Processor Time",
    InstanceName = "_Total"
};

float cpuUsage = cpuCounter.NextValue();

Note que na propriedade CategoryName é informado “Processor”, a categoria referente ao processador da máquina, e na propriedade CounterName, o contador que se refere à porcentagem do tempo de processamento. Em algumas categorias de Performance Counter é necessário especificar o nome da instância do contador, através da propriedade InstanceName, como é o caso da categoria “Processor” do exemplo acima, onde está sendo utilizado a instância “_Total”. Na minha máquina, para a categoria “Processor”, também estão disponíveis as instâncias “0″ e “1″, que se referem aos dois núcleos do meu AMD Athlon™ 64 X2 Dual Core Processor 6000+.

Na categoria “Memory” não é necessário especificar o nome da instância. Veja abaixo o exemplo de como obter a quantidade de memória disponível:

PerformanceCounter ramCounter = new PerformanceCounter
{
    CategoryName = "Memory",
    CounterName = "Available MBytes"
};

float availableRam = ramCounter.NextValue();

Para recuperar todas as categorias disponíveis para medição, use o método GetCategories da classe PerformanceCounterCategory:

PerformanceCounterCategory[] categories;
categories = PerformanceCounterCategory.GetCategories();

A partir de uma categoria, você pode recuperar todas os nomes de contadores. Por exemplo, o código abaixo:

var category = new PerformanceCounterCategory("System");

foreach (PerformanceCounter counter in category.GetCounters())
{
    Console.WriteLine(counter.CounterName);
}

Gera a seguinte saída:

File Read Operations/sec
File Write Operations/sec
File Control Operations/sec
File Read Bytes/sec
File Write Bytes/sec
File Control Bytes/sec
Context Switches/sec
System Calls/sec
File Data Operations/sec
System Up Time
Processor Queue Length
Processes
Threads
Alignment Fixups/sec
Exception Dispatches/sec
Floating Emulations/sec
% Registry Quota In Use

Eu fiz duas aplicações console de exemplo utilizando Performance Counters:

  • Uma exibe a porcentagem de uso da CPU e a quantidade de MB de memória disponíveis, atualizando as informações a cada um segundo;
  • A outra lista todos os nomes de instâncias e contadores de algumas categorias.

Você pode baixar essas duas aplicações aqui.


Post original:
http://prodis.pro.br/2009/05/04/como-medir-o-uso-da-cpu-utilizando-performance-counters

.

Ruby in Steel, brincando com Ruby e Rails no Visual Studio 2008

Quarta-feira, 29 de abril de 2009 por Mauricio de Amorim

Para quem ainda está em dúvida se Ruby é legal ou porque ele é legal, e se é mais fácil desenvolver com Rails para Web ou não, aqui estão algumas dicas para fazer algumas “brincadeiras” nas horas de folga. Garanto que estas brincadeiras vão virar um vício em pouco tempo.
Ruby é uma linguagem apaixonante, mesmo para quem está começando, é muito fácil para escrever e a sensação é que as coisas vão fluindo tranquilamente e “sem dor”.

Detalhe, Ruby in Steel é um produto para o Visual Studio da Microsoft, existe a versão comercial, mas nos links abaixo tudo é “free”, de graça, isto mesmo. Claro que é uma versão minimalista com pouco recursos, mas o suficiente para iniciar a transição. Por quê iniciar a transição? Teste Ruby e teste o Ruby on Rails e logo, logo, Terminal será seu nome e Editor de Texto seu sobrenome, IDE será coisa do passado.

IDE Visual Studio 2008 com Ruby

Esta versão do Ruby in Steel inclui a versão Express (gratuita) do Visual Studio 2008.
Ruby in Steel – Personal Edition 2008

O e-book do Huw CollingBourne também é free, e explica Ruby de uma maneira fácil para quem desenvolve em .Net.
The book of Ruby – Jan 2009

Post original:
http://mauriciodeamorim.com.br/2009/04/11/brincando-com-ruby-e-rails-no-visual-studio-2008/

Grupo de .NET

Quarta-feira, 11 de março de 2009 por AkitaOnRails

Recentemente ministrei uma palestra sobre Ruby on Rails para um grupo de arquitetos de .Net. Eles se reúnem periodicamente na Unip, na região da USP, para discutir sobre assuntos de tecnologia e arquitetura, com ênfase em plataforma .NET.

Eles mantém um site http://www.dotnetarchitects.net/ onde publicam as palestras que fazem nos seus encontros. Desta vez eu falei sobre Rails, mas nas reuniões anteriores falaram sobre Team System.

Um dos organizadores é o Giovanni Bassi, que é conhecido na comunidade .Net. Veja neste link sobre como participar tanto das reuniões presenciais quanto do Grupo de Discussão que eles mantém. Eles estão sempre atualizados e é um ótimo fórum para falar sobre ASP.NET MVC, Dynamic Data, NHibernate, LINQ, DDD, SOLID e muito mais. Aproveitem.

QCon – Frameworks and DDD: Keeping the Model Clean

Segunda-feira, 24 de novembro de 2008 por Fernando Hamasaki de Amorim

Atualização em 30/04/2009: O vídeo da apresentação está disponível no site InfoQ:
http://www.infoq.com/presentations/Clean-Model-Tim-McCarthy

Tim McCarthy é autor de “.NET Domain-Driven Design with C#: Problem – Design – Solution“, um livro que propõe mostrar os passos da implementação de uma aplicação real utilizando DDD. O livro é dividido em módulos, cada um identificando um problema, elaborando o design e implementando a solução.

Em sua apresentação, ele mostrou algumas técnicas para desacoplar o modelo de domínio da infra-estrutura da aplicação e ainda sim continuar usando recursos de frameworks em .NET.

Frameworks and DDD: Keeping the Model Clean - Tim McCarthy

A idéia é sempre deixar o domínio intacto, somente com o código do coração do software. Se você utilizar as famosas ferramentas de “arrastar e soltar”, vai poluir as entidades do domínio com código de infra-estrutura.

Quando falou a respeito do ADO.NET Entity Framework, o novo framework de mapeamento objeto-relacional da Microsoft, Tim se expressou indignado: “Oh, my God!”. Segundo ele, arrastar e soltar tabela por tabela do seu banco de dados, deixando o Visual Studio gerar um monte de código para você é algo não muito bom para se fazer.

Essas ferramentas de geração de código podem ser uma armadilha para desenvolvedores inexperientes. Para sistemas pequenos, sem grandes pretensões, isso pode ser uma solução rápida e que atende sua necessidade. Mas para grandes aplicações é preciso se concentrar no domínio e eliminar qualquer código que polua suas entidades de negócio.

Não é uma boa idéia criar um modelo de domínio fazendo a relação de uma entidade por tabela no banco de dados. As tabelas do banco de dados pertencem à infra-estrutura do sistema. O seu modelo de domínio deve ser rico e refletir seu negócio, o mais próximo da realidade possível. A partir do seu modelo de domínio é que você constrói uma infra-estrutura de persistência de dados.

A apresentação de Tim McCarthy foi repleta de exemplos reais (e rodando) de código. Num deles, mostrou uma classe de entidade do domínio onde havia uma referência using para o namespace Microsoft.SharePoint. Esse foi um tipico exemplo de entidade de negócio poluída.

Também tivemos um exemplo de utilização de repositórios (Repository), que segundo Tim, são um tipo de abstração da persistência, comparando-os como um tipo de coleção de dados, onde é possível listar, inserir, alterar e remover seus itens. Ele enfatizou que o classes do modelo de domínio podem usar repositórios, mas elas devem estar ligadas somente às interfaces dos repositórios, não acopladas às suas implementações.

Outra parte “prática” da apresentação foi a utilização de injeção de dependência (Dependency Injection) de repositórios nas classes de serviço e alteração do tipo de persistência via arquivo de configuração.

Tim também mostrou a implementação de uma unidade de trabalho (Unit of Work), onde a mesma não conversava diretamente com a base de dados.

A apresentação excedeu 10 minutos do tempo previsto, pois tinha muito código interessante a ser mostrado. Isso só acabou instigando a dar uma olhada no seu livro, que vem com o código fonte de todos os passos de construção de uma aplicação em .NET aplicando os padrões de DDD.

Só não esqueça que todo esse código somente vai poder lhe ajudar se você definir bem seu modelo de domínio, consistente e conciso com a realidade do seu negócio.
.

QCon – TDD in a DbC World

Sexta-feira, 21 de novembro de 2008 por carlos.mendonca

Quinta-feira, durante a track sobre .NET, Greg Young falou sobre Design by Contract (DbC) como metodologia para enriquecer o TDD. Para isso ele apresentou o Spec#, uma linguagem desenvolvida pela Microsoft Research e usada, entre outros projetos, no sistema operacional Singularity (sim, o Windows e o Windows CE não são os únicos sistemas operacionais da Microsoft). O Spec# está sendo descontinuado, mas as funcionalidades de DbC estão sendo portadas para o C# em forma de bibliotecas.

A idéia fundamental aqui é que com TDD você quer testar behaviour (comportamento) e constraint (restrição). Imagine um método que não pode receber argumentos nulos. Tipicamente você colocaria um bloco if e caso o argumento fosse nulo você lançaria algo como uma ArgumentNullException, mas antes deveria ter criado um teste para o caso do seu método receber o argumento nulo.

Agora imagine que você tenha, através da linguagem, um modo de estabelecer os contratos dos métodos. Neste caso você poderia escrever algo assim:

void SomeMethod(object someArgument)
    requires someArgument != null;
{
    // …
}

Esta palavra-chave requires é uma pré-condição (ou um guard). Ele estabelece um contrato que diz que o método SomeMethod não pode ser chamado caso o argumento someArgument seja nulo. Há vários outros tipos de contrato como invariantes e pós-condições, mas o importante de se entender aqui é que se o compilador for inteligente o suficiente para interpretar esta informação adicional, ele será capaz de fazer uma análise estática e determinar se o método SomeMethod é inválido ou pode ser inválido por causa do argumento que está recebendo de quem o está chamando.

Isto é especialmente poderoso, pois introduziria a “luz amarela” no seu ciclo de desenvolvimento TDD e eliminaria vários testes que com DbC são redundantes. Como se fala no mundo ágil que você deveria apenas testar o que possui business value, essas condições de contorno não precisariam ser testadas, pois seriam cobertas pelo DbC (a menos que as condições de contorno possuam, excepcionalmente, algum business value).

Inversão de controle com Unity

Sexta-feira, 18 de julho de 2008 por carlos.mendonca

No último post iniciamos nossa breve visita ao “Enterprise Library 4.0” com o “Cryptography Application Block”. Neste post vamos analisar o “Unity Application Block” que é uma novidade na versão 4 da biblioteca. O “Unity” é um container de inversão de controle baseado na biblioteca “ObjectBuilder2” do “Entreprise Library” e que foi lançado como uma alternativa às já tradicionais bibliotecas “Spring.NET” (uma versão da famosa biblioteca Spring do mundo Java), “Castle Windsor”, “StructureMap”, “ObjectBuilder” etc.

Quem já utilizava o “Enterprise Library” em alguma de suas versões anteriores deve estar familiarizado com a biblioteca “ObjectBuilder”. Ela atuava no núcleo do “Enterprise Library” cuidando do gerenciamento dos objetos e apesar de não ser um “cidadão de primeira classe” (já que não era promovido como um dos conjuntos de aplicação), podia ser referenciado e utilizado diretamente pelo usuário. Muitos reclamavam de questões relativas ao design e performance da biblioteca e, a partir do feedback dos usuários e observação dos projetos da comunidade, a Microsoft refez o código e lançou o “ObjectBuilder2”. Baseado nele, foi construído o “Unity Application Block” e a novidade é que apesar de fazer parte do “Enterprise Library”, pode ser baixado separadamente através do portal CodePlex.

Conforme mencionei, o “Unity” é apenas uma alternativa a outras bibliotecas. Dito isto, podemos esperar muitas funcionalidades parecidas, algumas inéditas e algumas que faltam. A intenção deste post não é fazer uma comparação entre todas as bibliotecas disponíveis, mas visitar algumas das funcionalidades básicas do “Unity” para que seja mais fácil explorar daí pra frente.

Usando o “Unity Application Block”

Após baixar e instalar o pacote do CodePlex, vamos criar um novo ConsoleApplication no Visual Studio 2008 e referenciar as duas bibliotecas principais do “Unity” que já estão registradas no GAC da máquina: Microsoft.Practices.Unity, Microsoft.Practices.Unity.Configuration e Microsoft.Practices.Unity.ObjectBuilder2.

Para iniciarmos com um exemplo, vamos imaginar uma aplicação simples onde queremos criar um log. Podemos ter várias implementações deste “logger”, por exemplo, uma que escreve as mensagens direto no console e outra que escreve em um arquivo texto. Se fizermos com que estes dois “loggers” implementem uma interface comum, ganhamos flexibilidade por podermos especificar através de um arquivo de configuração qual gostaríamos de usar.

Esta seria a interface em questão:

public interface ILogger
{
    void Log(string message);
}

Há apenas um método que recebe a mensagem que gostaríamos de escrever. Para ela, criamos duas implementações:

public class ConsoleLogger : ILogger
{
    public void Log(string message)
    {
        Console.WriteLine(message);
    }
}
public class TextFileLogger : ILogger
{
    public void Log(string message)
    {
        using (StreamWriter streamWriter =
new StreamWriter("log.txt", true))
        {
            streamWriter.WriteLine(message);
        }
    }
}

Se utilizarmos apenas a interface ILogger, já podemos escrever o comportamento da nossa prova de conceito:

ILogger logger;
logger.Log("Aplicação foi iniciada.");
logger.Log("Aplicação foi finalizada.");

Falta apenas inicializar o objeto logger. Para isso, utilizaremos as classes do namespace Microsoft.Practices.Unity, de forma que o método Main fica assim:

static void Main(string[] args)
{
    UnityContainer unityContainer = new UnityContainer();
    unityContainer.RegisterType(typeof (ILogger),
typeof (ConsoleLogger));
    ILogger logger = unityContainer.Resolve<ILogger>();
    logger.Log("A aplicação foi iniciada.");
    Console.ReadLine();
    logger.Log("A aplicação foi finalizada.");
}

Vamos analisar passo-a-passo o que fizemos: em primeiro lugar, inicializamos o objeto unityContainer com o construtor padrão. Depois, configuramos programaticamete o Unity através do método RegisterType. Neste caso, criamos a associação dizendo que a interface ILogger deve ser associada à implementação ConsoleLogger. Ao rodar o programa, podemos ver que as mensagens são impressas na tela. Seriam impressas no arquivo log.txt se a associação da interface ILogger fosse com a implementação TextFileLogger.

A princípio, a menos que a intenção seja aproveitar o controle do ciclo de vida dos objetos que o Unity fornece (para encapsular nossa implemenação em um singleton, ou pedir uma instância por chamada), não há muito sentido em configurá-lo programaticamente. O código equivalente a este, mas com as configurações no App.config seria o seguinte:

static void Main(string[] args)
{
    UnityContainer unityContainer = new UnityContainer();

    UnityConfigurationSection unityConfigurationSection =
(UnityConfigurationSection) ConfigurationManager.GetSection("unity");
unityConfigurationSection.Containers.Default.Configure(unityContainer);
    ILogger logger = unityContainer.Resolve<ILogger>();
    logger.Log("A aplicação foi iniciada.");
    Console.ReadLine();
    logger.Log("A aplicação foi finalizada.");
}
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="unity" type=
"Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
Microsoft.Practices.Unity.Configuration" />
  </configSections>
  <unity>
    <typeAliases>
      <typeAlias alias="ILogger"
type="ConsoleApplication1.ILogger, ConsoleApplication1" />
      <typeAlias alias="ConsoleLogger"
type="ConsoleApplication1.ConsoleLogger, ConsoleApplication1" />
      <typeAlias alias="TextFileLogger"
type="ConsoleApplication1.TextFileLogger, ConsoleApplication1" />
    </typeAliases>
    <containers>
      <container>
        <types>
          <type type="ILogger" mapTo="ConsoleLogger" />
        </types>
      </container>
    </containers>
  </unity>
</configuration>

Com este exemplo iniciamos a utilização do Unity, mas ainda há muitos recursos a explorar. Na seção de links, ao final do post, há uma lista de blogs que possuem exemplos de aplicação que estendem o que já fizemos. Uma modificação imediata que poderíamos fazer seria especificar o nome do arquivo log.txt através do próprio arquivo App.config, bastando apenas passá-lo através de um construtor da classe ConsoleLogger.


Switch to our mobile site