O objetivo principal desse artigo é aprimorar técnicas existentes de programação para que, no futuro, tenhamos uma eficiente e correta comunicação entre a DLL criada e um projeto de ambiente web
Para que seja desenvolvida a DLL é preciso, inicialmente, supor que ela assuma alguma funcionalidade e, nesse caso, ela será responsável por controlar as transações do aplicativo web para um banco de dados que, por padrão, pode ser o Microsoft SQL Server, desde que tenha instalado seu gerenciador, o chamado SQL Server Management Studio.
A proposta é criar um novo banco de dados com o nome de ServiceDesk (nome próprio que identificará facilmente a nova base de dados) e em sequência a tabela Funcionario, de acordo com o modelo de diagrama de classe apresentado na Figura 1.
Criando Tabela no SQL Server
Para criar a tabela Funcionario no SQL Server Management Studio, caso a versão instalada esteja em inglês, é só clicar em New Query (nova consulta) e depois colocar o código descrito na Listagem 1. Finalmente, clique em Execute (localizado no canto superior) ou pressione a tecla F5 - que é a tecla de atalho para execução de comandos SQL.
CREATE TABLE [dbo].[Funcionario](
[fun_codigo] [int] IDENTITY(1,1) NOT NULL,
[fun_nome] [varchar](70) NOT NULL,
[fun_dtcontratacao] [datetime] NOT NULL,
[fun_dtdemissao] [datetime] NOT NULL,
[fun_ativo] [char](1) NOT NULL,
[fun_senha] [varchar](15) NOT NULL,
[fun_tipo] [char](1) NOT NULL,
CONSTRAINT [PK_Funcionario] PRIMARY KEY CLUSTERED
(
[fun_codigo] ASC
)WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
Após isso, é necessário que sejam inseridas algumas informações no interior do banco de dados, pois posteriormente a aplicação web pode ser responsável por trazer para o usuário ou enviar essas informações para a tabela e, com nenhuma informação, a aplicação retornará nula ou com erro.
Criando um Novo Projeto
Agora, depois de ter o Microsoft Visual Studio instalado, é preciso criar um novo projeto para a criação da DLL. Neste exemplo será utilizado a versão 10 deste ambiente de desenvolvimento. No menu superior (se a versão estiver em inglês) vá em File → New → Project (Arquivo → Novo → Projeto). Após isso, aparecerá uma janela para escolha da forma de um novo projeto: selecione a aba Windows para abrir o menu Windows Forms Control Library. Dê um Name (nome), Location (localização) e um Solution name (nome para solução), deixando selecionado a opção “Create directory for solution” (dizendo que é para criar um diretório para solução) e clique em OK, como mostra a Figura 2.
Depois, aparecerá um arquivo chamado UserControl1.cs que é padrão na hora da criação de um novo projeto Windows Forms Control Library. Esse arquivo criado e presente no Solution Explorer pode ser excluído do projeto.
Feito isso, é preciso criar três pastas (Folders): uma com o nome de Controller (que será a responsável pelo Controlador), a segunda com o nome de DAO (que será a responsável pelo acesso, envio e manipulação de dados) e a terceira com o nome de Model (que será a responsável pelo Modelo), como mostra a Figura 3.
Criação se Classes
A proposta agora é criar as classes dentro de cada pasta, na qual cada uma é responsável por fazer sua funcionalidade.
Na pasta DAO serão criadas as classes: Banco.cs e FuncionarioBD.cs , onde a classe FuncionarioBD.cs será responsável pela manipulação de dados e comandos de SQL (insert, update, delete), e a classe Banco.cs será responsável por conectar com o banco de dados.
Para a classe Banco.cs podemos implementar os códigos referentes a Listagem 2.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.SqlClient;
using System.Data;
namespace ServiceDesk.DAO
{
internal class Banco
{
private string _strConexao;
private SqlCommand _comandoSQL;
protected SqlCommand ComandoSQL
{
get { return _comandoSQL; }
set { _comandoSQL = value; }
}
private SqlConnection _conn;
private SqlTransaction _transacao;
protected Banco()
{
_strConexao = @"Data Source=localhost\sqlexpress;Initial Catalog=ServiceDesk;
Persist Security Info=True;User ID=sa;Password=a12345z";
_conn = new SqlConnection(_strConexao);
_comandoSQL = new SqlCommand();
_comandoSQL.Connection = _conn;
}
protected Banco(string stringConexao)
{
_strConexao = stringConexao;
_conn = new SqlConnection(_strConexao);
_comandoSQL = new SqlCommand();
_comandoSQL.Connection = _conn;
}
protected bool AbreConexao(bool transacao)
{
try
{
_conn.Open();
if (transacao)
{
_transacao = _conn.BeginTransaction();
_comandoSQL.Transaction = _transacao;
}
return true;
}
catch
{
return false;
}
}
protected bool FechaConexao()
{
try
{
if (_conn.State == ConnectionState.Open)
_conn.Close();
return true;
}
catch
{
return false;
}
}
protected void FinalizaTransacao(bool commit)
{
if (commit)
_transacao.Commit();
else
_transacao.Rollback();
FechaConexao();
}
~Banco()
{
FechaConexao();
}
protected int ExecutaComando(bool transacao)
{
if (_comandoSQL.CommandText.Trim() == string.Empty)
throw new Exception("Não há instrução SQL a ser executada.");
int retorno;
AbreConexao(transacao);
try
{
retorno = _comandoSQL.ExecuteNonQuery();
}
catch(Exception ex)
{
retorno = -1;
throw new Exception("Erro ao executar o comando SQL:", ex);
}
finally
{
if (!transacao)
FechaConexao();
}
return retorno;
}
protected int ExecutaComando(bool transacao, out int ultimoCodigo)
{
if (_comandoSQL.CommandText.Trim() == string.Empty)
throw new Exception("Não há instrução SQL a ser executada.");
int retorno;
ultimoCodigo = 0;
AbreConexao(transacao);
try
{
ultimoCodigo = Convert.ToInt32(_comandoSQL.ExecuteScalar());
retorno = 1;
}
catch(Exception ex)
{
retorno = -1;
throw new Exception("Erro ao executar o comando SQL: ", ex);
}
finally
{
if (!transacao)
FechaConexao();
}
return retorno;
}
protected DataTable ExecutaSelect()
{
if (_comandoSQL.CommandText.Trim() == string.Empty)
throw new Exception("Não há instrução SQL a ser executada.");
AbreConexao(false);
DataTable dt = new DataTable();
try
{
dt.Load(_comandoSQL.ExecuteReader());
}
catch(Exception ex)
{
dt = null;
throw new Exception("Erro ao executar o comando SQL: ", ex);
}
finally
{
FechaConexao();
}
return dt;
}
protected double ExecutaScalar()
{
if (_comandoSQL.CommandText.Trim() == string.Empty)
throw new Exception("Não há instrução SQL a ser executada.");
AbreConexao(false);
double retorno;
try
{
retorno = Convert.ToDouble(_comandoSQL.ExecuteScalar());
}
catch(Exception ex)
{
retorno = -1;
throw new Exception("Erro ao executar o comando SQL: ", ex);
}
finally
{
FechaConexao();
}
return retorno;
}
}
}
Vamos entender a lógica por traz da Listagem 2:
- O campo _strConexao é responsável pela definição da string de conexão;
- O campo _comandoSQL é responsável pelo comando de SQL a ser executado;
- A propriedade ComandoSQL é que expõe o campo para definição do comando de SQL a ser executado;
- O campo _conn define o objeto de conexão;
- O campo _transacao define o objeto de transação;
- O construtor Banco() define uma string de conexão fixa e cria os objetos de conexão e para cada configuração do banco de dados há um ID e Password (senha);
- O construtor Banco(string stringConexao) recebe por parâmetro a string de conexão a ser utilizada e cria os objetos de comando e conexão;
- O método AbreConexao(bool transacao) abre a conexão com o banco de dados;
- O método FechaConexao() fecha a conexão com o banco de dados;
- O método FinalizaTransacao(bool commit) finaliza uma transação;
- O destrutor ~Banco() fecha a conexão com o banco de dados;
- O método ExecutaComando(bool transacao) é responsável pela execução dos comandos de Insert, Update e Delete e Retorna um número inteiro que indica a quantidade de linhas afetadas;
- O método ExecutaComando(bool transacao, out int ultimoCodigo) é responsável pela execução dos comandos de Insert com retorno do último código cadastrado e Retorna um número inteiro que indica a quantidade de linhas afetadas;
- O método ExecutaSelect() é responsável pela execução dos comandos de Select e Retorna um DataTable com o resultado da operação;
- O método ExecutaScalar() é que executa comandos de Select para retornos escalares, ou seja, retorna a primeira linha e primeira coluna do resultado do comando de Select. Para esse exemplo, esse valor é convertido para Double. Ao final, retorna a primeira linha e primeira coluna do resultado comando de Select;
Para a classe FuncionarioBD.cs será implementado os códigos referentes a Listagem 3.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ServiceDesk.Model;
using System.Data;
namespace ServiceDesk.DAO
{
internal class FuncionarioBD : Banco
{
internal FuncionarioBD() { }
internal Funcionario Autenticar(int codigo, string senha)
{
ComandoSQL.Parameters.Clear();
ComandoSQL.CommandText = @"select * from FUNCIONARIO
where fun_codigo = @codigo and fun_senha = @senha";
ComandoSQL.Parameters.AddWithValue("@codigo", codigo);
ComandoSQL.Parameters.AddWithValue("@senha", senha);
DataTable dt = ExecutaSelect();
if (dt != null && dt.Rows.Count > 0)
{
Funcionario f = new Funcionario();
f.Codigo = Convert.ToInt32(dt.Rows[0]["fun_codigo"]);
f.Nome = dt.Rows[0]["fun_nome"].ToString();
f.DataContratacao = Convert.ToDateTime(dt.Rows[0]["fun_dtcontratacao"]);
if (dt.Rows[0]["fun_dtdemissao"] == DBNull.Value)
f.DataDemissao = null;
else
f.DataDemissao = Convert.ToDateTime(dt.Rows[0]["fun_dtdemissao"]);
f.Ativo = Convert.ToChar(dt.Rows[0]["fun_ativo"]);
f.Senha = dt.Rows[0]["fun_senha"].ToString();
f.Tipo = Convert.ToChar(dt.Rows[0]["fun_tipo"]);
return f;
}
else
return null;
}
internal int Gravar(Funcionario func)
{
ComandoSQL.Parameters.Clear();
if (func.Codigo == 0) //Novo registro
ComandoSQL.CommandText = @"insert into Funcionario
(fun_nome, fun_dtcontratacao, fun_ativo, fun_senha, fun_tipo)
values (@nome, @datacontratacao, @ativo, @senha, @tipo)";
else //Alteração
{
ComandoSQL.CommandText = @"update FUNCIONARIO
set fun_nome = @nome, fun_dtcontratacao = @datacontratacao, fun_dtdemissao =
@datademissao,
fun_ativo = @ativo, fun_senha = @senha, fun_tipo = @tipo
where fun_codigo = @codigo";
ComandoSQL.Parameters.AddWithValue("@codigo", func.Codigo);
if (func.DataDemissao == null)
ComandoSQL.Parameters.AddWithValue("@datademissao", DBNull.Value);
else
ComandoSQL.Parameters.AddWithValue("@datademissao", func.DataDemissao);
}
ComandoSQL.Parameters.AddWithValue("@nome", func.Nome);
ComandoSQL.Parameters.AddWithValue("@datacontratacao", func.DataContratacao);
ComandoSQL.Parameters.AddWithValue("@ativo", func.Ativo);
ComandoSQL.Parameters.AddWithValue("@senha", func.Senha);
ComandoSQL.Parameters.AddWithValue("@tipo", func.Tipo);
return ExecutaComando(false);
}
internal List<Funcionario> Obter(string palavraChave, char ativo)
{
ComandoSQL.Parameters.Clear();
ComandoSQL.CommandText = @"select fun_codigo, fun_nome, fun_dtcontratacao,
fun_dtdemissao, fun_ativo, fun_senha, fun_ativo, fun_tipo
from Funcionario
where fun_ativo = @ativo and fun_nome like @palavra order by fun_nome";
ComandoSQL.Parameters.AddWithValue("@ativo", ativo);
ComandoSQL.Parameters.AddWithValue("@palavra", "%"+palavraChave+"%");
DataTable dt = ExecutaSelect();
List<Funcionario> dados = null;
if (dt != null && dt.Rows.Count > 0)
{
dados = new List<Funcionario>();
foreach(DataRow linha in dt.Rows)
{
Funcionario f = new Funcionario();
f.Codigo = Convert.ToInt32(linha["fun_codigo"]);
f.Nome = linha["fun_nome"].ToString();
f.DataContratacao = Convert.ToDateTime(linha["fun_dtcontratacao"]);
if (linha["fun_dtdemissao"] == DBNull.Value)
f.DataDemissao = null;
else
f.DataDemissao = Convert.ToDateTime(linha["fun_dtdemissao"]);
f.Ativo = Convert.ToChar(linha["fun_ativo"]);
f.Senha = linha["fun_senha"].ToString();
f.Tipo = Convert.ToChar(linha["fun_tipo"]);
dados.Add(f);
}
}
return dados;
}
internal int Demitir(int codigoFuncionario)
{
ComandoSQL.Parameters.Clear();
ComandoSQL.CommandText = @"update Funcionario set fun_ativo = 'N',
fun_demissao = @data where fun_codigo = @codigo";
ComandoSQL.Parameters.AddWithValue("@data", DateTime.Now);
ComandoSQL.Parameters.AddWithValue("@codigo", codigoFuncionario);
return ExecutaComando(false);
}
internal Funcionario Obter(int codigoFuncionario)
{
ComandoSQL.Parameters.Clear();
ComandoSQL.CommandText = @"select fun_codigo, fun_nome, fun_dtcontratacao,
fun_dtdemissao, fun_ativo, fun_senha, fun_ativo, fun_tipo
from Funcionario
where fun_codigo = @codigo";
ComandoSQL.Parameters.AddWithValue("@codigo", codigoFuncionario);
DataTable dt = ExecutaSelect();
if (dt != null && dt.Rows.Count > 0)
{
Funcionario f = new Funcionario();
f.Codigo = Convert.ToInt32(dt.Rows[0]["fun_codigo"]);
f.Nome = dt.Rows[0]["fun_nome"].ToString();
f.DataContratacao = Convert.ToDateTime(dt.Rows[0]["fun_dtcontratacao"]);
if (dt.Rows[0]["fun_dtdemissao"] == DBNull.Value)
f.DataDemissao = null;
else
f.DataDemissao = Convert.ToDateTime(dt.Rows[0]["fun_dtdemissao"]);
f.Ativo = Convert.ToChar(dt.Rows[0]["fun_ativo"]);
f.Senha = dt.Rows[0]["fun_senha"].ToString();
f.Tipo = Convert.ToChar(dt.Rows[0]["fun_tipo"]);
return f;
}
else
return null;
}
}
}
Agora, na pasta Controller, será criada a classe: FuncionarioController.cs, responsável por controlar a sua tabela, definindo as ações e regras de acesso, como se fosse uma validação interna entre a saída e entrada de dados. A classe FuncionarioController.cs será implementada conforme o código da Listagem 4.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ServiceDesk.Model;
using ServiceDesk.DAO;
namespace ServiceDesk.Controller
{
public class FuncionarioController
{
FuncionarioBD bd = new FuncionarioBD();
public Funcionario Autenticar(int codigo, string senha)
{
if (codigo > 0 && senha.Trim().Length > 0)
return new FuncionarioBD().Autenticar(codigo, senha);
else
return null;
}
public FuncionarioController() { }
public int Gravar(Funcionario func)
{
if (func.Nome.Trim().Length >= 3 &&
func.Ativo == 'S')
{
return bd.Gravar(func);
}
else
return -1;
}
public List<Funcionario> Obter(char ativo = 'S')
{
if (ativo == 'S' || ativo == 'N')
return bd.Obter("",ativo);
else
return null;
}
public Funcionario Obter(int codigoFuncionario)
{
return codigoFuncionario > 0 ? bd.Obter(codigoFuncionario) : null;
}
public int Demitir(int codigoFuncionario)
{
return bd.Demitir(codigoFuncionario);
}
}
}
Já na pasta Model será criada a classe Funcionario.cs, onde modelará as regras de negócio como se fosse um intermediário entre o lado Cliente e o lado Servidor e cada propriedade é responsável por receber e/ou enviar as informações. A classe Funcionario.cs será implementada de acordo com a Listagem 5.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ServiceDesk.Model
{
public class Funcionario
{
public Funcionario() { _codigo = 0; }
#region Propriedades do Funcionario
private int _codigo;
public int Codigo
{
get
{
return _codigo;
}
set
{
_codigo = value;
}
}
private string _nome;
public string Nome
{
get
{
return _nome;
}
set { _nome = value; }
}
private DateTime _dataContratacao;
public DateTime DataContratacao
{
get { return _dataContratacao; }
set { _dataContratacao = value; }
}
private DateTime? _dataDemissao;
public DateTime? DataDemissao
{
get { return _dataDemissao; }
set { _dataDemissao = value; }
}
private char _ativo;
public char Ativo
{
get { return _ativo; }
set { _ativo = value; }
}
private string _senha;
public string Senha
{
get { return _senha; }
set { _senha = value; }
}
private char _tipo;
public char Tipo
{
get { return _tipo; }
set { _tipo = value; }
}
#endregion
}
}
Por fim, após ter criado todas as classes relativas a tabela Funcionário, o layout dos arquivos ficará como mostra a Figura 4.
Criando a DLL ServiceDesk
Finalmente, para que o projeto se transforme em uma DLL, basta dar um Build e salvar. Com isso, ela pode ser utilizada em qualquer projeto web ASP .NET.
Para anexar essa DLL criada a um projeto web ASP .NET, basta clicar com o botão direito em References do novo projeto e clicar em Add Reference..., como ilustra a Figura 5.
Feito isso, aparecerá uma janela, conforme mostra na Figura 6.
Após ter selecionado o Project Name, basta dar OK e a DLL criada estará na futura aplicação web ASP . NET.