Desenvolvendo Bibliotecas de Classe

Juliano Aéce
Outubro 2010

Tecnologias: Visual Studio 2010, .NET Framework 4

 

Sumário: Apresentarei nesse artigo como desenvolver nossas próprias bibliotecas de classe para que possamos usá-las em vários projetos. Desta forma economizamos código e tempo.

Baixe o código fonte

Conteúdo

arrow_down.gifIntrodução
arrow_down.gifTemplate Class Library
arrow_down.gifCriando um Projeto Class Library
arrow_down.gifAdicionando a Biblioteca
arrow_down.gifReferenciando a Biblioteca em um Projeto Windows Forms
arrow_down.gifCriando e Atribuindo um Strong Name ao Assembly
arrow_down.gifGlobal Assembly Cache
arrow_down.gifConclusão
arrow_down.gifReferências + Tópicos Relacionados
arrow_down.gifSobre o Autor

Introdução

Bibliotecas de Classe são classes que podemos utilizar em qualquer projeto .NET, são apropriadas quando queremos usar um bloco de código comum à várias aplicações. Imagine que temos um método complexo que usamos em várias aplicações, ao invés de criarmos esse método em todos os projetos podemos criar uma biblioteca de classe e referenciá-la nos projetos.

Template Class Library

É a templateClass Library que nos fornece a infra-estrutura para desenvolvimento de bibliotecas de classe. O assembly gerado por esse tipo de projeto é um arquivo Dynamic-Link Library (DLL). Podemos referenciar essa DLL em qualquer projeto .NET. O mais interessante é que podemos desenvolver uma DLL em Visual Basic.NET e consumí-la em um projeto C# e vice-versa sem problemas, pois ambas as linguagens são linguagens .NET.

Criando um Projeto Class Library

No Visual Studio clicamos no menu File, New, Project... e selecionamos a template Class Library. Vamos nomear nosso projeto de Financeiro (Figura 1).


Figura 1 – Criando um Projeto Class Library no Visual Studio 2010

Com essa template temos apenas uma classe chamada Class1 a qual podemos renomeá-la ou excluí-la. Neste caso vamos apenas renomeá-la para Pagamentos. Vamos também adicionar um método, CalcularSalário, que recebe como parâmetros uma string com o nome do funcionário, um int com a quantidade de horas trabalhadas, um int com o valor que ele recebe por hora trabalhada e um int com a quantidade de horas extra que ele fez. O cálculo é bem simples, veja como ficará nossa classe na listagem 1 abaixo:

namespace Financeiro
{
    public class Pagamentos
    {
        public decimal CalcularSalario(string nomeDoFuncionario, int horasTrabalhadas, 
            decimal valorPorHora, int horasExtra)
        {
            decimal salario;

            salario = (horasTrabalhadas * valorPorHora) + 
                ((horasExtra * valorPorHora) * 2);

            return salario;
        }
    }
}

Listagem 1 – Método CalcularSalario

Nossa DLL está pronta, se verificarmos o arquivo gerado, como disse acima deve ser um arquivo com extensão .dll. Na figura 2 podemos ver o arquivo Financeiro.dll:


Figura 2 – Arquivo .dll gerado

Agora nossa DLLestá pronta para usarmos em qualquer projeto .NET.

Adicionando a Biblioteca

Para adicionarmos nossa biblioteca em um projeto usamos o mesmo método que adicionamos referências do .NET Framework, na janela Solution Explorer clicamos com o botão direito do mouse na pasta Reference de nosso projeto e selecionamos a opção Add Reference... (figura 3). Na nova janela que é aberta temos várias abas (Figura 3):

  • .NET; Bibliotecas do Framework.

  • COM: Bibliotecas construídas em tecnologias não .NET

  • Projects: Bibliotecas contidas em projetos da mesma solução.

  • Browse: Buscar uma biblioteca no sistema de arquivos.

  • Recent: Histórico com as bibliotecas referenciadas recentemente.

Podemos adicionar essas referências em qualquer tipo de aplicação: Windows Forms, ASP.NET Web Applications, Console Application, WPF Application, etc.


Figura 3 – Add Reference...


Figura 4 – Janela Add Reference

Referenciando a Biblioteca em um Projeto Windows Forms

Vamos criar uma aplicação Windows Forms com um formulário bem simples apenas para demonstrar como funciona o uso de nossa bilioteca criada. Abaixo, na figura 5 podemos ver como ficará o formulário:


Figura 5 – Formulário

Agora vamos adicionar a nossa biblioteca através da janela Add Reference:


Figura 6 – Adicionando Referência

Após selecionarmos a biblioteca e clicarmos no botão OK, a biblioteca será referenciada ao nosso projeto podendo ser vista na janela Solution Explorer na pasta References, conforme mostra a figura 7 abaixo:


Figura 7 – Biblioteca referenciada

Agora chegou a hora de escrevermos alguns códigos. O intuito desse formulário que criamos é clicar no botão Calcular Salário e mostrar o valor do salário do funcionário no lblSalario conforme os dados fornecidos. Primeiro de tudo temos que referenciar (using) o namespace da nossa biblioteca que é o nome do projeto que criamos anteriormente conforme listagem 2:

using Financeiro;

Listagem 2 – Referenciando o Namespace

No evento Click do botão vamos capturar os valores digitados no formulário, instanciar a classe Pagamentos que pertence ao namespace Financeiro, ou seja, a classe de nossa biblioteca e por fim chamar o método CalcularSalario mostrando o resultado no formulário. Esse código podemos ver na listagem 3 abaixo:

private void btnCalcularSalario_Click(object sender, EventArgs e)
{
    string nomeDoFuncionario = this.txtNomeDoFuncionario.Text;
    decimal valorPagoPorHora = Convert.ToDecimal(this.txtValorPagoPorHora.Text);
    int horasTrabalhadas = Convert.ToInt32(this.txtHorasTrabalhadas.Text);
    int horasExtraTrabalhadas = Convert.ToInt32(this.txtHorasExtraTrabalhadas.Text);

    Pagamentos p = new Pagamentos();
    decimal salario = 
        p.CalcularSalario(nomeDoFuncionario, horasTrabalhadas, valorPagoPorHora,
            horasExtraTrabalhadas);

    this.lblSalario.Text = salario.ToString();
}

Listagem 3 – Evento Click

Como podemos ver na Figura 8, o fato de referenciar a biblioteca em nosso projeto faz com que o arquivo DLL seja copiado para a pasta do projeto:


Figura 8 – Arquivos do Projeto

O que não podemos fazer agora é renomear, excluir ou deixar a DLL em um diretório diferente da aplicação. O arquivo DLL por si só não trabalha, precisa ter uma aplicação consumindo essa DLL. Podemos simplesmente colocar os arquivos ConsumindoBiblioteca.exe (aplicação Windows Forms) e o arquivo Financeiro.dll (biblioteca de classe) em qualquer diretório, através dos instaladores fornecidos pelo .NET ou copiando e colando que a aplicação funcionará normalmente. O nosso projeto está funcionando perfeitamente mas temos um problema, imagine que no meu trabalho eles usam essa DLL para calcular os salários dos funcionários (inclusive o meu), eu sei o código da DLL e sou mau intencionado, então desenvolvo uma nova DLL alterando o método usado para calcular o salário que é CalcularSalário. Faço o seguinge: verifico se o nome do funcionário é Juliano Aece, se sim multiplico a hora extra por 3 e não por 2 como é o correto. Para ficar mais claro, na listagem 4 tem o código da minha nova DLL:

namespace Financeiro
{
    public class Pagamentos
    {
        public decimal CalcularSalario(string nomeDoFuncionario, int horasTrabalhadas,
            decimal valorPorHora, int horasExtra)
        {
            decimal salario;

            if (nomeDoFuncionario == "Juliano Aece")
            {
                salario = (horasTrabalhadas * valorPorHora) +
                    ((horasExtra * valorPorHora) * 3);
            }
            else
            {
                salario = (horasTrabalhadas * valorPorHora) +
                    ((horasExtra * valorPorHora) * 2); 
            }
            return salario;
        }
    }
}

Listam 4 – Código da DLL Alterado

Podemos substituir a DLL original por essa nova DLL (desde que o namespace, classe e método tenham os mesmos nomes e o método os mesmos parâmetros do método original) que tudo funcionará sem erros (figura 9), claro, com a alteração que eu fiz, ou seja, vão calcular o meu salário de forma incorreta. Resumindo, não temossegurança alguma. Para que isso não aconteça devemos atribuir um strong name à nossa DLL.


Figura 9 – Aplicação com DLL alterada

Criando e Atribuindo um Strong Name ao Assembly

Strong name fornece uma identificação única ao assembly. Isso previne conflitos de nomes e versões entre assemblies e ainda garante sua autenticidade o que impede que o mesmo seja substituido. O strong name é composto pelas seguintes informações:

  • Nome do assembly..

  • Número de versão do assembly.

  • Chave pública e assinatura digital.

  • Informação sobre a cultura do assembly.

Definindo strong name para assemblies permite múltiplas cópias do mesmo assembly com versões diferentes executando ao mesmo tempo no mesmo computador. Isso é conhecido como execução lado-a-lado (side-by-side execution). Para criarmos um strong name devemos utilizar o utilitário sn.exe através do Visual Studio Command Prompt para criar um par de chaves criptografadas. Primeiro vamos até a pasta que queremos salvar a chave e depois digitamos sn.exe –k chave.snk. “chave.snk” é o nome do arquivo a ser salvo. Abaixo, na figura 10 podemos ver a que a chave foi criada com sucesso:


Figura 10 – Criando chave

Com a chave criada devemos agora atribuir o strong name ao nosso assembly (DLL). Voltando ao projeto da biblioteca no Visual Studio, na janela Solution Explorer, clicamos com o botão direito do mouse em nosso projeto e selecionamos a opção Properties. Na janela de propriedades do projeto, temos uma guia na lateral esquerda chamada Signing, nessa guia temos a opção Sign the assembly, habilitando essa opção embaixo temos um ComboBox para selecionarmos a chave. Selecionamos Browse e adicionamos a chave que criamos no passo anterior que está na pasta C:\Temp. Depois de definida a chave basta compilar o projeto.
Nessa ComboBox onde selecionamos a chave temos outra opção, New, onde a partir daí podemos criar nossa chave ao invés de criarmos pelo utilitário sn.exe.
Agora no projeto Windows Forms, temos que referenciar a DLL novamente. Depois de todos esses passos se tentarmos substituir a DLL (mesmo que seja identica a original e que também tenha um strongname desde que o strong name não tenha sido atribuido com a mesma chave) a hora que clicarmos no botão Calcular Salário uma exceção será mostrada dizendo que a aplicação não encontra a DLL.
Podemos ter dois tipos de DLLs:

  • Private: DLLs private são DLLs que ficam salvas na mesma pasta que a aplicação que as consomem. Se tivermos três aplicações que consomem uma mesma DLL ela deverá ser copiada para os três diretórios das aplicações.

  • Shared: DLLs shared são DLLs que são compartilhadas entre várias aplicações. As DLLs compartilhadas são instaladas no Global Assembly Cache e todas as aplicações usam a mesma DLL.

Global Assembly Cache

Global Assembly Cache (também conhecido como GAC) é um repositório de assembly contido no .NET Framework, ou seja, esse repositório é instalado automaticamente quando o .NET Framework é instalado. Ele nada mais é uma pasta que contém assemblies (arquivos DLLs e EXEs). O mais interessante é que podemos (o .NET Framework faz isso) salvar DLLs de versões diferentes. Imagina o seguinte cenário: Temos duas aplicações no computador, uma usa a versão 1.0 da DLL e a outra usa a versão 2.0, se substituíssemos a DLL 1.0 pela 2.0 a primeira aplicação não funcionaria mais. Para instalar uma DLL no GAC obrigatóriamente essa DLL deve possuir um strong name. Podemos acessar o GAC pelo sistema de arquivos, C:\Windows\assembly (figura 11). Para instalar uma DLL no Gac, temos três opções:

  • Arrastar dentro do GAC.

  • Usar o utilitário gacutil.exe

  • Usar instaladores fornecidos pelo .NET Framework.

Instalando Assembly no GAC

O utilitário gacutil.exe deve ser usado apenas para instalações de assemblies em ambiente de desenvolvimento, nunca em produção. Abaixo, na figura 13 demonstro como usar o utilitário:


Figura 11 – Utiliário gacutil

Podemos também simplesmente arrastar o arquivo .dll para dentro da pasta C:\Windows\assembly. Usando instaladores do .NET Framework, no projeto de Setup, em File System on Target Machine, clicamos com o botão direito do mouse em cima e selecionamos a opção Add Special Folder,Global Assembly Cache Folder. Depois nessa pasta adicionada basta adicionarmos a(s) DLL(s). As figuras 12 e 13 abaixo demonstram isso:


Figura 12 – Adicionando Global Assembly Cache Folder


Figura 13 – Assembly na pasta Global Assembly Cache

O mais interessante é que quando instalamos a DLL no GAC não precisamos “informar” a aplicação que a DLL está lá pois automaticamente quando uma aplicação .NET depende de uma DLL primeiramente ela pesquisa no GAC se for encontrada a aplicação executará normalmente se não ela pesquisará no diretório da aplicação.

O GAC compartilha assemblies somente na máquina local. Só devemos instalar um assembly no GAC se o mesmo for compartilhado para várias aplicações, pois não faz sentido instalarmos um assembly no GAC se usamos ele apenas em uma aplicação, nesse caso deixamos o assembly no mesmo diretório da aplicação.

Conclusão

Se temos um bloco de código que se repete em vários projetos, ao invés de colocarmos esse código em todos os projetos fazemos uma biblioteca e a referenciamos em todos os projetos. Ainda se as aplicações que usarão essa biblioteca estiverem na mesma máquima podemos instalar essa biblioteca no GAC para que a mesma seja compartilhada.

Não podemos esquecer de deixar a chave que foi criada para atribuir o strong name em um local seguro, pois com ela qualquer desenvolvedor consegue facilmente atribuir o mesmo strong name a outro assembly. E claro, quando precisarmos recompilar nosso assembly devemos utilizar a mesma chave, senão teremos que referenciar o assembly (com novo strong name) novamente na aplicação.

Referências + Tópicos Relacionados

Global Assembly Cache: https://msdn.microsoft.com/en-us/library/yf1d93sz(v=VS.100).aspx

Sn.exe (Strong Name Tool): https://msdn.microsoft.com/en-us/library/k5b5tt23(v=VS.100).aspx

Gacutil.exe (Global Assembly Cache Tool): https://msdn.microsoft.com/en-us/library/ex0ss12c(v=VS.100).aspx

Sobre o Autor

Juliano Aéce, entusiasta por tecnologias Microsoft, é desenvolvedor de aplicações .NET há mais de dois anos. Atualmente trabalha em uma empresa do ramo da saúde e escreve artigos regularmente em seu blog (http://julianoaece.wordpress.com).

Pode ser contatado através do email julianoaece@yahoo.com.br.