Seções iMasters
.NET + C#

Criando uma aplicação ASP .NET em três camadas

Confira uma forma bem resumida de como criar uma aplicação ASP .NET em 3 camadas usando a linguagem C#. Acompanhe cada etapa e deixe suas impressões ao final do artigo.

O significa criar uma aplicação em camadas?

Quando acessa a página do seu banco na internet, você está usando uma aplicação que possui uma tela de apresentação, na qual o usuário recebe e entra com as informações.

  • Quando você faz o login na sua conta acessando a página do seu banco na internet, existe uma interface na qual você informa seu login e senha.
  • Quando você submete essa informação, a aplicação aplica as regras de negócios para verificar se seu login e senha são válidos.
  • Para isso, a aplicação consulta um cadastro de informações, que está em um banco de dados, e verifica se o que o usuário digitou corresponde ao que está no cadastro.

Com esse exemplo bem simples, podemos perceber que temos três partes distintas atuando:

  1. A interface representada pela tela de login solicitando login e senha.
  2. As regras de validação que serão aplicadas representando as regras de negócio.
  3. As informações armazenadas no cadastro representando o banco de dados.

A figura abaixo procura mostrar de forma resumida esses três componentes, identificando e nomeando cada um deles.

Podemos identificar as seguintes camadas:

  • Camada de Apresentação (Presentation Tier)
  • Camada de Negócios (Business Logic Tier)
  • Camada de Acesso a dados (Data Tier)

Embora para o cliente tudo seja apenas uma única aplicação, para o desenvolvedor criar uma aplicação em camadas significa desenvolver separadamente cada um dos componentes identificados no exemplo acima de forma a facilitar a manutenção e a ganhar produtividade.

Chama-se a isso uma aplicação com arquitetura em três camadas. Lembrando que podemos ter aplicações em n-camadas. Resumindo:

A arquitetura em três camadas é uma arquitetura cliente servidor na qual a interface do usuário, os processos de negócios e o armazenamento de dados são desenvolvidos e mantidos em módulos independentes, ou em plataforma separadas.

Basicamente existem três camadas:

  • Camada de apresentação: User Interface (UI)
  • Camada de Negócios: Business Logic Layer (BLL)
  • Camada de Acesso a dados: Data Access Layer (DAL)

Cada camada pode ser desenvolvida e testada separadamente. Para a nossa aplicação ASP .NET, podemos resumir a arquitetura em três camadas da seguinte forma:

  1. A camada de apresentação contém os elementos da interface do usuário do site e acrescenta toda a lógica que inclui a interação entre o visitante e as regras de negócio. (ASP .NET Web Forms, Users Controls e Master Pages)
  2. A camada de negócio (BLL) recebe a requisição da camada de apresentação e retorna o resultado dependendo da lógica de negócio. (Classes C#)
  3. A camada de acesso a dados contém as classes que acessam o banco de dados e retornam o resultado a camada de negócio. (Classes C#)

Criando a aplicação ASP .NET em três camadas

  • Definindo o banco de dados, a tabela e a stored procedure

Em nosso exemplo, iremos criar uma aplicação ASP .NET para gerenciar as informações de clientes existentes na tabela Clientes do banco de dados Macoratti.mdf do SQL Server. O script para gerar o banco de dados Macoratti.mdf e a tabela Clientes é apresentado abaixo:

CREATE DATABASE [Macoratti] ON PRIMARY
( NAME = N'Macoratti', FILENAME = N'c:Program FilesMicrosoft SQL ServerMSSQL10.SQLEXPRESSMSSQLDATAMacoratti.mdf' , SIZE = 3072KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB )
LOG ON
( NAME = N'Macoratti_log', FILENAME = N'c:Program FilesMicrosoft SQL ServerMSSQL10.SQLEXPRESSMSSQLDATAMacoratti_log.ldf' , SIZE = 1024KB , MAXSIZE = 2048GB , FILEGROWTH = 10%)
GO

USE [Macoratti]
GO

CREATE TABLE [dbo].[Clientes](
[id] [int] IDENTITY(1,1) NOT NULL,
[nome] [nvarchar](50) NULL,
[email] [nvarchar](150) NULL,
[nascimento] [date] NULL,
CONSTRAINT [PK_Clientes] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

Se você desejar incluir dados na tabela Clientes usando o SQL Server Management Studio, pode usar o seguinte script:

INSERT INTO [Macoratti].[dbo].[Clientes]
([nome]
,[email]
,[nascimento])
VALUES
(<nome, nvarchar(50),>
,<email, nvarchar(150),>
,<nascimento, date,>)
GO

Em VALUES, inclua os dados que deseja incluir. O banco de dados Macoratti.mdf foi criado no SQL Server Management Studio e nele também foi criado uma stored procedure chamada GetClientes, conforme mostra a figura abaixo:

Essa stored procedure GetClientes oferece acesso à tabela Clientes e retorna todos os registros da tabela.

Vamos usar o Visual Web Developer 2010 Express Edition para criar o nosso site. No menu File, clique em New Web Site e a seguir selecione a linguagem Visual C#, o template ASP .NET Empty Web Site, informe o nome ASPNET_3Camadas e clique no botão OK.

  • Criando o projeto no Visual Web Developer Express

Na janela Solution Explorer, você poderá ver a estrutura do projeto contendo apenas o arquivo web.config. Vamos incluir uma Master Page no projeto. No menu WebSite, selecione Add New Item e a seguir selecione o template Master Page, informe o nome Site.master e clique no botão Add.

Após incluir a Master Page, vamos incluir nela uma tabela com 3 linhas e 1 coluna a partir do menu Table->Insert Table, definindo na página o seguinte layout:

  • Definindo as Classes do projeto

Vamos agora definir três classes em nosso projeto:

  1. Configuração: classe responsável por obter a string de conexão e o nome do provedor usado.
  2. AcessoDados: classe que contém os métodos para acesso aos dados.
  3. Cliente: classe que irá chamar os métodos da classe AcessoDados.

Vamos criar uma nova pasta no projeto chamada App_Code para conter essas três classes.

A pasta App_Code é uma pasta especial na qual você pode armazenar seu código-fonte e ele será compilado automaticamente em tempo de execução.O assembly resultante está acessível a todos os outros códigos no aplicativo da Web. Dessa forma, a pasta App_Code funciona como a pasta Bin, exceto pela possibilidade de armazenar código-fonte nela em vez de código compilado.

A pasta App_Code e seu status especial em um aplicativo ASP.NET tornam possível criar classes personalizadas e outros arquivos que contém somente código-fonte e usá-los em seu aplicativo da Web sem ter que compilá-los independentemente.

A pasta App_Code pode conter quantos arquivos e sub-pastas quanto você precisar. Você pode organizar seu código-fonte de qualquer forma que você achar conveniente.

No menu WebSite, clique em Add ASP .NET Folder e selecione App_Code:

Criando a classe Configuracao.cs

Vamos agora criar a classe Configuracao.cs na pasta App_Code. Clique com o botão direito do mouse sobre a pasta App_Code e selecione Add New Item. Selecione o template Class, informe o nome Configuracao.cs e clique no botão Add. Em seguida, digite o código abaixo na classe Configuracao.cs:

using System.Configuration;

public static class Configuracao
{
private static string dbConnectionString;
private static string dbProviderName;

static Configuracao()
{
dbConnectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
dbProviderName = ConfigurationManager.ConnectionStrings["ConnectionString"].ProviderName;
}

public static string DbConnectionString
{
get { return dbConnectionString; }
}

public static string DbProviderName
{
get { return dbProviderName; }
}
}

Nesse código, estamos usando o namespace System.Configuration, pois vamos obter a string de conexão e o nome do provedor a partir do arquivo de configuração Web.Config.

Vamos então abrir o arquivo Web.Config e incluir na seção connectionStrings a string de conexão para acesso ao banco de dados Macoratti, além do nome do provedor conforme abaixo:

<connectionStrings>
<add name="ConnectionString" connectionString="Data Source=.SQLEXPRESS;Initial Catalog=Macoratti;Integrated Security=True" providerName="System.Data.SqlClient"/>
</connectionStrings>

Criando a classe AcessoDados.cs

Clique com o botão direito do mouse sobre a pasta App_Code e selecione Add New Item. Selecione o template Class, informe o nome AcessoDadaos.cs e clique no botão Add. Em seguida, digite o código abaixo na classe AcessoDados.cs:

using System;
using System.Data;
using System.Data.Common;

namespace Macoratti
{
public static class AcessoDados
{
static AcessoDados()
{
}

//Cria um commando
public static DbCommand CreateCommand()
{
string dbProviderName = Configuracao.DbProviderName;
string dbConnectionString = Configuracao.DbConnectionString;
DbProviderFactory factory = DbProviderFactories.GetFactory(dbProviderName);
DbConnection connection = factory.CreateConnection();
connection.ConnectionString = dbConnectionString;
DbCommand command = connection.CreateCommand();
command.CommandType = CommandType.StoredProcedure;
return command;
}

public static DataTable ExecuteReader(DbCommand command)
{
DataTable table;
try
{
command.Connection.Open();
DbDataReader reader = command.ExecuteReader();
table = new DataTable();
table.Load(reader);
}
catch (Exception ex)
{ throw ex; }
finally
{ command.Connection.Close(); }
return table;
}

public static int ExecuteNoneQuery(DbCommand command)
{
int linhasAfetadas = -1;
try
{
command.Connection.Open();
linhasAfetadas = command.ExecuteNonQuery();
}
catch (Exception ex)
{ throw ex; }
finally
{ command.Connection.Close(); }
return linhasAfetadas;
}

public static string ExecuteScalar(DbCommand command)
{
string valor = "";
try
{
command.Connection.Open();
valor = command.ExecuteScalar().ToString();
}
catch (Exception ex)
{ throw ex; }
finally
{ command.Connection.Close(); }
return valor;
}
}
}

Nessa classe, definimos 4 métodos para acessar os dados:

  • CreateCommand: cria um novo comando a partir do nome do provedor

O método CreateCommand() é do tipo DbCommand e cria um novo comando usando uma fábrica de provedores, além de utilizar o nome do provedor e a string de conexão para criar um comando para o provedor definido no arquivo Web.Config.

O novo modelo de provedor disponível a partir da ADO.NET 2.0 está baseado em um série de classes base no namespace System.Data.Comom. A classe DBProviderFactories permite a realização de dois tipos de tarefas:

  1. Obter uma lista de todos os provedores existentes via método estático GetFactoryClasses
  2. Criar uma instância de um determinado Factory conforme o seu tipo via método GetFactoryClass

Uma classe base de provedor é um objeto factory, que é usado para criar um conjunto de objetos relacionados como SqlConnection e SqlCommand. Eles retornam um tipo de classe abstrata do tipo DBConnection.

As classes de provider factory são derivadas de uma classe base abstrata: System.Data.Common.DbProviderFactory. Para cada tipo de base de dados a ser acessado, temos uma nova classe derivada dessa classe base abstrata. A classe DbDataProvider define o número de funções que essa subclasse precisa implementar:

CreateComand() Cria um objeto
Command derivado de DBCommand.
CreateCommandBuilder() Cria um objeto derivado de DbCommandBuilder
CreateConnection() Cria um objeto
derivado de DbConnection.
CreateConnectionStringBuilder() Cria um objeto
derivado de DbConnectionStringBuilder
CreateDataAdapter() Cria um objeto
derivado de DbDataAdapter.
CreateDataSourceEnumerator() Cria um objeto
derivado de DbDataSourceEnumerator.
CreateParameter() Cria um objeto
derivado de DbParameter.
CreatePermission() Cria um objeto
derivado de CodeAccessPermission,
             Funções
DbDataProvider

Desde que o DbProviderFactory apropriado foi criado, a função na tabela acima pode ser usada para criar o objeto apropriado em vez de usar o operador New como anteriormente. Para determinar todas as classes DbProviderFactory disponíveis e criar suas classes adicionais, é fornecida a classe System.Data.Common.DbProviderFactories.

Cada provedor de dados faz o registro de uma classe ProviderFactory no arquivo machine.config da plataforma .NET. A classe base DbProviderFactory e a classe ProviderFactories podem retornar um DataTable de informações sobre os diferentes provedores registrados no arquivo machine.config. Eles podem recuperar a ProviderFactory conforme a sequência do provedor fornecida ou um DataRow de um DataTable.

  • ExecuteReader: retorna um DataTable usando para instruções SELECT com objetivo de obter os dados retornado por consultas SQL usando SELECT

O método ExecuteReader possui um parâmetro DbCommand. Esse comando irá obter um DataTable resultado da consulta SELECT. O DbDataReader irá ler todos os dados a partir das tabelas e finalmente o comando irá retornar o resultado como um DataTable.

  • ExecuteNonQuery: usado para instruções INSERT, UPDATE, DELETE. Neste caso, não teremos dados retornados apenas as linhas(registros) que foram afetadas
  • ExecuteScalar: usado para obter somente o primeiro dado retornado pela consulta SELECT

Criando a classe Cliente.cs

Clique com o botão direito do mouse sobre a pasta App_Code e selecione Add New Item. Selecione o template Class, informe o nome Cliente.cs e clique no botão Add. Em seguida, digite o código abaixo na classe Cliente.cs:

using System.Data;
using System.Data.Common;

namespace Macoratti
{
public class Cliente
{
public static DataTable GetClients()
{
DbCommand command = AcessoDados.CreateCommand();
command.CommandText = "GetClientes";
return AcessoDados.ExecuteReader(command);
}
}
}

Nesse código, criamos um comando para usar a stored procedure GetClientes, criada no banco de dados Macoratti.mdf. A seguir, executamos o método ExecuteReader da classe AcessoDados que retornar um DataTable com os dados dos clientes.

Definindo a camada de apresentação

Vamos incluir no projeto um novo Web Forms para exibir as informações da tabela Clientes usando as classes que criamos nos tópicos anteriores. No menu WebSite, clique em Add New Item e a seguir selecione o template Web Form. Informe o nome ListaClientes.aspx, marque a opção Select master page e clique no botão Add.

A seguir, selecione a master page Site.master e clique em OK.

Em seguida, na página ListaClientes.aspx, inclua um controle GridView alterando seu ID para gdvClientes. A seguir, abra o arquivo ListaClientes.aspx.cs e defina o código abaixo no evento Load da página:

namespace Macoratti
{

public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
gdvClientes.DataSource = Cliente.GetClientes();
gdvClientes.DataBind();
}
}
}

Pegue o projeto completo Versão C# e compartilhe seus experimentos em três camadas.

Até a próxima! 

Comente também

8 Comentários

Juliano Marcon

Muito bom o artigo. Se me permite, acredito que nos próximos poderia adicionar a motivação para utilização da arquitetura de camadas.

A manutenabilidade é um ponto extremamente forte desta arquitetura, mas a produtividade inicial é algo discutível.

Outros ponto que acho que deveria ser citado é a Injeção de Dependências (facilitada pela divisão das camadas) e exposição da camada de negócios através de outros meios senão web.forms, ou seja, poderia no mesmo sistema utilizando a mesma camada de negócios ter um site, um webservice de integração de dados e uma aplicação de gerenciamento em WPF.

Peço desculpas pela intromissão e sou um grande admirador de seu trabalho. Comecei na programação vendo artigos seus.

    David Oliveira

    Para exemplificar/motivar a utilização dessa arquitetura, podemos partir do ponto em que é verdade dizer: Codificar tudo junto ou em camadas é quase a mesma coisa no sentido quantitativo, ou seja, se temos que escrever uma rotina de validação ela será quase a mesma em tamanho sendo tudo junto ou em uma camada separada.

    Indo um pouco além, vamos imaginar o senário de um projeto com grandes módulos e uma equipe de três pessoas, com a arquitetura em 3 camadas seria possível a divisão do módulo de modo que todos da equipe poderiam fazer pequenas partes e ao final da sprint ter algo pronto ao passo que se cada membro da equipe tivesse com um módulo, ao final da sprint nenhum teria terminado, ou seja, nada pronto.

    Hoje estou em um projeto com mais 3 analistas em que em cada sprint(1mês) implementamos 1 ou 2 módulos. Se não utilizássemos essa arquitetura teríamos que cada um pegar um módulo separadamente e levaríamos no mínimo 3 meses para ter algo pronto. Então, realmente a produtividade inicial é algo discutível, mas ao meu ver essa arquitetura não compromete em nada esse ponto.

Vinicius Serpa

Concordo com o Juliano, poderíamos aprofundar essa arquitetura. Poderíamos inclusive fazer um paralelo do o uso de DAO com o Entity Framework. Quanto à motivação, o tempo de desenvolvimento mais longo seria justificada pela economia na fase de manutenção, a qual pode estar presente em aproximadamente 90% do ciclo de vida da aplicação.

Amaury Gomes

David Oliveira, senário com “s”? Pelo amor de Deus!!!

sergio

gostei muito, tenho uma aplicação rodando em minha empresa produzido por terceiro, consegui rodá-lo como backup em uma maquina virtual, sem o conhecimento da programação em camada. posso agora começar a entrar a fundo neste mundo de programação em camadas, obrigado pela ajuda com este tutorial.

henrique

ola

tenho vontade, de aprender asp.net, mas, material as vezes, é diferente das verções diferente de que tenho instaldo no meu pc, pode me ajudar

Salomão Manjate

Este projecto existe na versão VB.net. Gosto deste programação que envolve DbProviderFactory/Dbfactory. Estou ansioso em ver como vai usar CRUD com estas ferramentas (DbproviderFactory/Dfactor) em VB.net. Para já vai o meu obrigado pelo que já nos foi apresentado! Onde temos referencias para CRUD com DbProviderFactory factory ? Muito obrigado. Lembre-se de nós quando tartar do CRUD com DbProviderFactory factory de trazê-lo em VB.net.
Obrigago, Sr. Jose Carlos Macoratti

Nsimba Pedro

Gostei muito desse projeto,porque o programador explica duma maneira clara mesmo não entendo a programação tu endentes,é uma pagina que estou adense volver para o meu trabalho do fim do curso.

Qual a sua opinião?