ASP .NET  - Criando e implementando uma arquitetura em 3 camadas - II


Neste artigo vou mostrar como criar e implementar uma arquitetura em 3 camadas em uma aplicação ASP .NET Web Forms usando o VS Community 2015.

Vamos continuar a criação da nossa aplicação ASP .NET em 3 camadas, iniciada na primeira parte do artigo, começando pela definição do modelo de domínio na camada DTO.

1- Implementando o modelo de domínio na camada DTO

Vamos definir o domínio da nossa aplicação criando as classes que representam o nosso modelo de negócios. Para tornar o cenário mais leve vou focar em uma modelo bem simples onde iremos gerenciar as informações dos clientes.

Dessa forma, vamos criar uma classe Cliente com propriedades que representam as informações que vamos gerenciar.

Selecione o projeto DTO e renomeie a classe Class1.cs para Cliente.cs e inclua o código a seguir:

    public class Cliente
    {
        public int Id { get; set; }
        public string nome { get; set; }
        public string endereco { get; set; }
        public string telefone { get; set; }
        public string email { get; set; }
        public string observacao { get; set; }
    }

Essa classe será usada para armazenar e transferir informações do cliente entre as camadas da aplicação.

Vamos agora definir a camada de acesso a dados.

2- Implementando o acesso e a persistência aos dados na camada DAL

Considere que eu estou usando uma abordagem bem simples, sem criar repositório, nem usar uma ferramenta ORM como o Entity Framework. Estou por assim dizer, no arroz com feijão, usando ADO .NET de uma forma bem simples.

A camada de acesso a dados é responsável pelo acesso e persistência de informações no banco de dados usado pela aplicação. No nosso exemplo vamos utilizar o SQL Server 2012 onde teremos um banco de dados Cadastro.mdf e uma tabela Clientes com a seguinte estrutura:

CREATE TABLE [dbo].[Clientes](
	[Id] [int] IDENTITY(1,1) NOT NULL,
	[Nome] [nvarchar](80) NOT NULL,
	[Endereco] [nvarchar](100) NULL,
	[Telefone] [nvarchar](50) NULL,
	[Email] [nvarchar](150) NULL,
	[Observacao] [nvarchar](250) NULL,
 CONSTRAINT [PK_Clientes] PRIMARY KEY CLUSTERED 

O banco de dados e a tabela podem ser criados no próprio ambiente do Visual Studio através da janela Server Explorer.

A string de conexão com o banco de dados para o nosso exemplo é definida como : "Data Source=.\sqlexpress;Initial Catalog=Cadastro;Integrated Security=True"

Nota: A string de conexão pode variar no seu ambiente.

Vamos armazenar a string de conexão no arquivo de configuração Web.Config da aplicação WEB no projeto WebUI criando uma seção <connectionString> conforme abaixo:

...
<connectionStrings>
  <add name="conexaoSQLServer" connectionString="Data Source=.\sqlexpress;Initial Catalog=Cadastro;Integrated Security=True" providerName="System.Data.SqlClient"/>
</connectionStrings>
...

Nota: Antes de executar o procedimento a seguir verifique no seu projeto DAL o item References e veja se a referência a System.Configuration já foi incluída.

Para poder acessar e obter o valor da string de conexão no arquivo Web.Config temos que incluir uma referência ao namespace System.Configuration no projeto DAL.

Clique com o botão direito sobre o projeto DAL e selecione Add Reference;

Na janela Add Reference clique em Assemblies e selecione o item System.Configuration clicando no botão OK:

Portanto as ações para acessar, incluir, alterar e excluir dados deverão ser feitas, exclusivamente, pela camada de acesso a dado a dados.

Para isso vamos criar uma classe no projeto DAL chamada AcessoDB.vb

Esta classe deverá ter somente referências a classes para acesso a dados e não deverá conter nenhuma referência a outras classes.

using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
namespace Aspnet3Camadas.DAL
{
    public class AcessoDB
    {
        private static SqlConnection GetDbConnection()
        {
            try
            {
                string conString = ConfigurationManager.ConnectionStrings["conexaoClienteSQLServer"].ConnectionString;
                SqlConnection connection = new SqlConnection(conString);
                connection.Open();
                return connection;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        public static IDataReader ExecuteReader(string sql)
        {
            IDataReader reader = null;
            using (SqlConnection connection = GetDbConnection())
            {
                try
                {
                    using (SqlCommand command = new SqlCommand(sql, connection))
                    {
                        reader = command.ExecuteReader();
                    }
                }
                catch
                {
                    throw;
                }
                return reader;
            }
        }
        public int ExecuteNonQuery(string sql)
        {
            int i = -1;
            using (SqlConnection connection = GetDbConnection())
            {
                try
                {
                    using (SqlCommand command = new SqlCommand(sql, connection))
                    {
                        i = command.ExecuteNonQuery();
                    }
                }
                catch
                {
                    throw;
                }
                return i;
            }
        }
        public static DataSet ExecuteDataSet(string sql)
        {
            DataSet ds = null;
            using (SqlConnection connection = GetDbConnection())
            {
                try
                {
                    using (SqlCommand Command = new SqlCommand(sql, connection))
                    {
                        ds = ExecuteDataSet();
                    }
                }
                catch
                {
                    throw;
                }
                return ds;
            }
        }
        public static DataSet ExecuteDataSet()
        {
            SqlDataAdapter da = null;
            IDbCommand cmd = new SqlCommand();
            DataSet ds = null;
            try
            {
                da = new SqlDataAdapter();
                da.SelectCommand = (SqlCommand)cmd;
                ds = new DataSet();
                da.Fill(ds);
            }
            catch
            {
                throw;
            }
            return ds;
        }
        public static DataTable GetDataTable(string sql, string[] parameterNames, string[] parameterVals)
        {
            using (SqlConnection connection = GetDbConnection())
            {
                using (SqlDataAdapter da = new SqlDataAdapter(sql, connection))
                {
                    DataTable table = new DataTable();
                    FillParameters(da.SelectCommand, parameterNames, parameterVals);
                    da.Fill(table);
                    return table;
                }
            }
        }
        public static DataTable GetDataTable(string sql)
        {
            using (SqlConnection connection = GetDbConnection())
            {
                using (SqlDataAdapter da = new SqlDataAdapter(sql, connection))
                {
                    DataTable table = new DataTable();
                    da.Fill(table);
                    return table;
                }
            }
        }
        public static string SelectScalar(string sql, string[] parameterNames, string[] parameterVals)
        {
            using (SqlConnection connection = GetDbConnection())
            {
                using (SqlCommand command = new SqlCommand(sql, connection))
                {
                    FillParameters(command, parameterNames, parameterVals);
                    return Convert.ToString(command.ExecuteScalar());
                }
            }
        }
        public static string SelectScalar(string sql)
        {
            using (SqlConnection connection = GetDbConnection())
            {
                using (SqlCommand command = new SqlCommand(sql, connection))
                {
                    return Convert.ToString(command.ExecuteScalar());
                }
            }
        }
        public static int CRUD(string sql, string[] parameterNames, string[] parameterVals)
        {
            try
            {
                using (SqlConnection connection = GetDbConnection())
                {
                    using (SqlCommand command = new SqlCommand(sql, connection))
                    {
                        FillParameters(command, parameterNames, parameterVals);
                        return command.ExecuteNonQuery();
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        private static void FillParameters(SqlCommand command, string[] parameterNames, string[] parameterVals)
        {
            try
            {
                if (parameterNames != null)
                {
                    for (int i = 0; i <= parameterNames.Length - 1; i++)
                    {
                        command.Parameters.AddWithValue(parameterNames[i], parameterVals[i]);
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    }
}

A classe AcessoDB possui diversos métodos que acessam, retornam e persistem informações em um banco de dados SQL Server. É uma classe bem básica que usa os recursos da ADO .NET.

A maioria dos métodos usa o modificador Shared indicando que o método é estático, e, que portanto, não é um método de instância, dessa forma não precisamos criar uma instância da classe AcessoDB para ter acesso aos métodos, basta informar o nome da classe seguida de ponto e o nome do método: AcessoDB.GetDataTable().

Você pode criar uma DAL que ao invés de retornar objetos DataTable, DataSet, DataReader, etc., retorne objetos de negócio usando os recursos do Generics da plataforma .NET. Poderíamos também abstrair todo o código ADO .NET usando o Entity Framework, mas neste artigo, como eu já disse, eu estou tratando do arroz com feijão e não do camarão.

O conteúdo da classe que faz o papel da DAL pode variar dependendo do cenário de sua aplicação. Como a classe esta em uma camada separada das demais qualquer alteração feita nesta classe não deve alterar as classes das outras camadas.

Essa classe será chamada e referenciada pela camada de negócios(BLL) para realizar quaisquer operações com o banco de dados. Vamos então agora criar a camada de negócios.

3- Definindo as funcionalidades da Camada de Negócios - BLL

Na camada de negócios - BLL - iremos ter as classes que tratam as regras de negócio da aplicação. Vamos criar uma interface ICliente.cs onde iremos definir os contratos que deverão ser implementados pela classe ClienteBLL que será a classe que irá realizar o tratamento das regras de negócio da aplicação.

Remova a classe Class1.cs do projeto e no menu PROJECT clique em Add Class e selecione o template Interface informando o nome ICliente.cs e clicando no botão Add:

    public interface ICliente<T>
    {
        DataTable ExibirTodos();
        List<T> Exibir();
        void Incluir(T obj);
        void Alterar(T obj);
        void Excluir(T obj);
        DataTable Consultar(string nome);
        Cliente GetClienteId(int id);
    }

Nesta interface temos a referência ao namespace DTO onde definimos a classe Cliente.

A interface declara métodos contendo apenas a assinatura que deverão se implementados por uma classe concreta. Nossa interface é uma lista genérica do tipo T onde T representa uma classe que nosso exemplo será a classe Cliente.

O método Exibir() retorna uma lista genérica do tipo T, o método GetClienteId() retorna um tipo Cliente e os métodos Incluir(), Alterar() e Excluir() recebem como argumento um objeto do tipo T.

Para implementar essa interface vamos criar a classe ClienteBLL via menu PROJECT clicando em Add Class e selecionando o template Class.

Abaixo temos o código da classe concreta ClienteBLL que implementa a interface ICliente:

using Aspnet3Camadas.DAL;
using Aspnet3Camadas.DTO;
using System;
using System.Collections.Generic;
using System.Data;
namespace Aspnet3Camadas.BLL
{
    public class ClienteBLL : ICliente<Cliente>
    {
        public Cliente GetClienteId(int id)
        {
            try
            {
                string sql = "SELECT Id,Nome,Endereco,Telefone,Email,Observacao FROM Clientes WHERE Id = " + id;
                DataTable tabela = new DataTable();
                tabela = AcessoDB.GetDataTable(sql);
                return GetCliente(tabela);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        public Cliente GetCliente(DataTable tabela)
        {
            try
            {
                Cliente _Cliente = new Cliente();
                if (tabela.Rows.Count > 0)
                {
                    _Cliente.Id = Convert.ToInt32(tabela.Rows[0][0]);
                    _Cliente.nome = Convert.ToString(tabela.Rows[0]["Nome"]);
                    _Cliente.endereco = tabela.Rows[0][2].ToString();
                    _Cliente.telefone = tabela.Rows[0][3].ToString();
                    _Cliente.email = tabela.Rows[0][4].ToString();
                    _Cliente.observacao = tabela.Rows[0][5].ToString();
                    return _Cliente;
                }
                else
                {
                    _Cliente = null;
                    return _Cliente;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        public List<Cliente> Exibir()
        {
            try
            {
                string sql = "SELECT * FROM Clientes";
                DataTable tabela = new DataTable();
                tabela = AcessoDB.GetDataTable(sql);
                return GetListaCliente(tabela);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        public List<Cliente> GetListaCliente(DataTable tabela)
        {
            try
            {
                List<Cliente> listaCliente = new List<Cliente>();
                int i = 0;
                dynamic registros = tabela.Rows.Count;
                if (registros > 0)
                {
                    foreach (DataRow drRow in tabela.Rows)
                    {
                        Cliente _Cliente = new Cliente();
                        _Cliente.Id = Convert.ToInt32(tabela.Rows[i][0]);
                        _Cliente.nome = Convert.ToString(tabela.Rows[i]["Nome"]);
                        _Cliente.endereco = tabela.Rows[i][2].ToString();
                        _Cliente.telefone = tabela.Rows[i][3].ToString();
                        _Cliente.email = tabela.Rows[i][4].ToString();
                        _Cliente.observacao = tabela.Rows[i][5].ToString();
                        listaCliente.Add(_Cliente);
                    }
                    while (i <= registros)
                    {
                        Cliente _Cliente = new Cliente();
                        _Cliente.Id = Convert.ToInt32(tabela.Rows[i][0]);
                        _Cliente.nome = Convert.ToString(tabela.Rows[i]["Nome"]);
                        _Cliente.endereco = tabela.Rows[i][2].ToString();
                        _Cliente.telefone = tabela.Rows[i][3].ToString();
                        _Cliente.email = tabela.Rows[i][4].ToString();
                        _Cliente.observacao = tabela.Rows[i][5].ToString();
                        listaCliente.Add(_Cliente);
                        i += i;
                    }
                    return listaCliente;
                }
                else
                {
                    listaCliente = null;
                    return listaCliente;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        public DataTable ConsultarPorID(int id)
        {
            string sql = "SELECT Id,Nome,Endereco,Telefone,Email,Observacao FROM Cliente WHERE Id = " + id;
            try
            {
                return AcessoDB.GetDataTable(sql);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        public DataTable Consultar(string nome)
        {
            string sql = "SELECT Id,Nome FROM Cliente WHERE Nome LIKE '" + nome + "%'" + " ORDER BY Nome";
            try
            {
                return AcessoDB.GetDataTable(sql);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        public void Incluir(Cliente oCliente)
        {
            string sql = "";
            try
            {
                string[] parametrosNomes = new string[6];
                parametrosNomes[0] = "@Nome";
                parametrosNomes[1] = "@Endereco";
                parametrosNomes[2] = "@Telefone";
                parametrosNomes[3] = "@Email";
                parametrosNomes[4] = "@Observacao";
                string[] parametrosValores = new string[6];
                parametrosValores[0] = oCliente.nome;
                parametrosValores[1] = oCliente.endereco;
                parametrosValores[2] = oCliente.telefone;
                //
                parametrosValores[3] = oCliente.email;
                parametrosValores[4] = oCliente.observacao;
                sql = "INSERT INTO Cliente(Nome,Endereco,Telefone,Email,Observacao) values (@Nome,@Endereco,@Telefone,@Email,@Observacao)";
                AcessoDB.CRUD(sql, parametrosNomes, parametrosValores);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        public void Alterar(Cliente oCliente)
        {
            string sql = "";
            try
            {
                string[] parametrosNomes = new string[7];
                parametrosNomes[0] = "@Id";
                parametrosNomes[1] = "@Nome";
                parametrosNomes[2] = "@Endereco";
                parametrosNomes[3] = "@Telefone";
                parametrosNomes[4] = "@Email";
                parametrosNomes[5] = "@Observacao";
                string[] parametrosValores = new string[7];
                parametrosValores[0] = oCliente.Id.ToString();
                parametrosValores[1] = oCliente.nome;
                parametrosValores[2] = oCliente.endereco;
                parametrosValores[3] = oCliente.telefone;
                //
                parametrosValores[4] = oCliente.email;
                parametrosValores[5] = oCliente.observacao;
                sql = "UPDATE Cliente SET Nome=@Nome, Endereco=@Endereco ,Telefone=@Telefone,Email=@Email , Observacao=@Observacao Where Id=@Id";
                AcessoDB.CRUD(sql, parametrosNomes, parametrosValores);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        public void Excluir(Cliente oCliente)
        {
            string sql = "";
            try
            {
                string[] parametrosNomes = new string[1];
                parametrosNomes[0] = "@Id";
                string[] parametrosValores = new string[1];
                parametrosValores[0] = oCliente.Id.ToString();
                sql = "DELETE FROM Cliente Where Id=@Id";
                AcessoDB.CRUD(sql, parametrosNomes, parametrosValores);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public DataTable ExibirTodos()
        {
            string sql = "SELECT * FROM Clientes";
            try
            {
                return AcessoDB.GetDataTable(sql);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    }
}

Note que os métodos usam a classe AcessoDB seguida do nome do método desejado.

Eu estou usando instruções SQL no formato texto definindo a instrução em uma variável para tornar mais simples o código, mas isso não é uma boa prática pois esta sujeita a injeção SQL.  Outra opção seria utilizar stored procedures que teria algumas vantagens e que eu vou abordar em outro artigo.

No próximo artigo podemos definir as funcionalidades da camada de apresentação - WebUI - que irá usar os recursos das demais camadas.

Mas, ó homem, quem és tu, que a Deus replicas? Porventura a coisa formada dirá ao que a formou: Por que me fizeste assim?
Ou não tem o oleiro poder sobre o barro, para da mesma massa fazer um vaso para honra e outro para desonra?

Romanos 9:20,21

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

Quer aprender a criar aplicações Web Dinâmicas usando a ASP .NET MVC 5 ?

 

  Gostou ?   Compartilhe no Facebook   Compartilhe no Twitter

 

Referências:


José Carlos Macoratti