ASP .NET - Criando uma aplicação em 3 Camadas (VB .NET)


Neste artigo eu vou mostrar de forma bem resumida como criar uma aplicação ASP .NET em 3 camadas usando a linguagem VB .NET.

O que significa criar uma aplicação em camadas ?

Quando você acessa a página do seu banco na internet esta usando uma aplicação que possui uma tela de apresentação onde você, 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 onde você informa seu login e senha.
- Quando você submete esta informação a aplicação aplica as regras de negócios para verificar se seu login e senha são válidos.
- Para isso ele consulta um cadastro de informações, que esta em um banco de dados, e verifica se o que o usuário digitou corresponde ao que esta no cadastro;

Com esse exemplo bem simples podemos perceber que temos 3 partes distintas atuando:

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

A figura abaixo procura mostrar de forma resumida esses 3 componentes identificando e nomeando cada um deles;

Podemo 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 (você), 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 ganhar produtividade.

Chama-se a isso uma aplicação com arquitetura em 3 camadas. (Podemos ter aplicações em n-camadas)

Resumindo:

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

Basicamente existem 3 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 3 camadas da seguinte forma:

1- A camada de apresentação contém os elementos da interface do usuário do site e inclui 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# ou VB .NET)

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# ou VB .NET)

Criando a aplicação ASP .NET em 3 camadas

1-) 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 é dado a seguir:

CREATE DATABASE [Macoratti] ON PRIMARY
( NAME = N'Macoratti', FILENAME = N'c:\Program Files\Microsoft SQL Server\MSSQL10.SQLEXPRESS\MSSQL\DATA\Macoratti.mdf' , SIZE = 3072KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB )
LOG ON
( NAME = N'Macoratti_log', FILENAME = N'c:\Program Files\Microsoft SQL Server\MSSQL10.SQLEXPRESS\MSSQL\DATA\Macoratti_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 acesso a 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 Basic , o template ASP .NET Empty Web Site, informe o nome ASPNET_3Camadas e clique no botão OK;

2-) 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 Project 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 leiaute:

3-) Definindo as Classes do projeto

Vamos agora definir 3 classes em nosso projeto:

Vamos criar uma nova pasta no projeto chamada App_Code para conter essas 3 classes.

A pasta App_Code é uma pasta especial onde 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, desta forma a pasta App_Code funciona como a pasta Bin, exceto que você pode armazenar código-fonte nela em vez de código compilado.

A pasta App_Code e seu status especial em um aplicativo ASP.NET torna 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.vb e clique no botão Add;

Em seguida digite o código abaixo na classe Configuracao.vb:

Public NotInheritable Class Configuracao

 

Private Sub New()

End Sub

Private Shared m_dbConnectionString As String

Private Shared m_dbProviderName As String

Shared Sub New()

   m_dbConnectionString = ConfigurationManager.ConnectionStrings("SQLConnectionString").ConnectionString

   m_dbProviderName = ConfigurationManager.ConnectionStrings("SQLConnectionString").ProviderName

End Sub


Public
Shared ReadOnly Property DbConnectionString() As String

  Get

     Return m_dbConnectionString

   End Get

End Property


Public
Shared ReadOnly Property DbProviderName() As String

   Get

     Return m_dbProviderName

   End Get

End Property
 

End Class

Neste 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;

Como podemos ter mais de uma string de conexão definida no arquivo web.config usamos o nome da string de conexão SQLConnectionString para identificar a  string de conexão com o banco de dados SQL Server.

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 e o nome do provedor conforme abaixo:

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

Observe que a string de conexão é identificada pelo nome SQLConnectionString.

- Criando a classe AcessoDados.vb

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.vb e clique no botão Add;

Em seguida digite o código abaixo na classe AcessoDados.vb:

Imports System

Imports System.Data

Imports System.Data.Common
 

Public NotInheritable Class AcessoDados


Private
Sub New()

End Sub


Shared
Sub New()

End Sub


Public
Shared Function ExecuteReader(ByVal command As DbCommand) As DataTable

   Dim table As DataTable

  Try

     command.Connection.Open()

     Dim reader As DbDataReader = command.ExecuteReader()

     table = New DataTable()

     table.Load(reader)

  Catch ex As Exception

    Throw ex

  Finally

     command.Connection.Close()

   End Try

  Return table

End Function

 

'Cria um commando

Public Shared Function CreateCommand() As DbCommand

  Try

     Dim dbProviderName As String = Configuracao.DbProviderName

      Dim dbConnectionString As String = Configuracao.DbConnectionString

      Dim factory As DbProviderFactory = DbProviderFactories.GetFactory(dbProviderName)

      Dim connection As DbConnection = factory.CreateConnection()

      connection.ConnectionString = dbConnectionString

      Dim command As DbCommand = connection.CreateCommand()

      command.CommandType = CommandType.StoredProcedure

      Return command

   Catch ex As Exception

      Throw ex

   End Try

 End Function

 

Public Shared Function ExecuteNoneQuery(ByVal command As DbCommand) As Integer

   Dim linhasAfetadas As Integer = -1

   Try

       command.Connection.Open()

       linhasAfetadas = command.ExecuteNonQuery()

   Catch ex As Exception

     Throw ex

   Finally

       command.Connection.Close()

   End Try

  Return linhasAfetadas

End Function

 

Public Shared Function ExecuteScalar(ByVal command As DbCommand) As String

   Dim valor As String = ""

  Try

     command.Connection.Open()

     valor = command.ExecuteScalar().ToString()

   Catch ex As Exception

     Throw ex

   Finally

       command.Connection.Close()

   End Try

  Return valor

End Function
 

End Class

Nesta classe definimos 4 métodos para acessar os dados:

a- 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 usando 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 esta 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. 1 Obter uma lista de todos os provedores existentes via método estático GetFactoryClasses;
  2. 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 , e , para cada tipo de base de dados a ser acessado temos uma nova classe derivada desta classe base abstrata. A classe DbDataProvider define o número de funções  que esta 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 ao invés de usar o operador New como anteriormente.(Para determinar todas as classes DbProviderFactory disponíveis e criar suas classes adicionais é fornecido 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 e podem recuperar a ProviderFactory conforme a sequência do provedor fornecida ou um DataRow de um DataTable.

b- ExecuteReader - Retorna um DataTable usando para instruções SELECT para obter os dados retornado por consultas SQL usando SELECT;

O método ExecuteReader possui um parâmetro DbCommand; este 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.

c- ExecuteNonQuery - Usado para instruções INSERT, UPDATE, DELETE. Nesta caso não teremos dados retornados apenas as linhas(registros) que foram afetadas;
d- ExecuteScalar
- Usado para obter somente o primeiro dado retornado pela consulta SELECT;

- Criando a classe Cliente.vb

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.vb e clique no botão Add;

Em seguida digite o código abaixo na classe Cliente.vb:

Imports System.Data

Imports System.Data.Common


Public
Class Cliente


Public
Shared Function GetClientes() As DataTable

   Dim command As DbCommand = AcessoDados.CreateCommand()

   command.CommandText = "GetClientes"

   Return AcessoDados.ExecuteReader(command)

End Function
 

End Class

Neste código criamos um comando para usar a stored procedure GetClientes que criamos 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.

4-) 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 e 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 de defina o código abaixo no evento Load da página:

Public Class _Default
   
Inherits System.Web.UI.Page

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

   gdvClientes.DataSource = Cliente.GetClientes()
   gdvClientes.DataBind()

End Sub
End
Class

 Executando o projeto iremos obter:

Acessando um banco de dados Microsoft Access

Para mostrar a flexibilidade da nossa aplicação vamos ver  como podemos acessar outro banco de dados. O banco de dados Northwind.mdb.

Vamos acessar a tabela Products e exibir na página ASP .NET os 10 produtos da tabela Products exibindo seu código, nome e preço unitário.

Para fazer isso devemos realizar as seguintes alterações em nosso projeto:

1 - Definir a string de conexão para o Microsoft Access no arquivo web.config

<connectionStrings>

<add name="SQLConnectionString"

connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=Northwind;Integrated Security=TrueproviderName="System.Data.SqlClient" />

<add name="OLEDBConnectionString"

connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\dados\Northwind.mdb" providerName="System.Data.OleDb" />

</connectionStrings>

Acima temos a nova string de conexão para o banco de dados Northwind.mdb identificada por: OLEDBConnectionString.

2- Alterar a classe Configuracao.vb para chamar a string de conexão com o Microsoft Access

Public NotInheritable Class Configuracao


Private Sub New()

End Sub
 

Private Shared m_dbConnectionString As String

Private Shared m_dbProviderName As String


Shared
Sub New()

   m_dbConnectionString = ConfigurationManager.ConnectionStrings("OLEDBConnectionString").ConnectionString

   m_dbProviderName = ConfigurationManager.ConnectionStrings("OLEDBConnectionString").ProviderName

End Sub
 

Public Shared ReadOnly Property DbConnectionString() As String

  Get

    Return m_dbConnectionString

  End Get

End Property
 

Public Shared ReadOnly Property DbProviderName() As String

  Get

    Return m_dbProviderName

End Get

End Property

End Class

Alteramos o nome da string de conexão para OLEDBConnectionString, dessa forma a conexão com o Microsoft Access será usada.

Obs: Eu poderia melhorar mais ainda alterando a classe para receber como parâmetro o nome da string de conexão. Que tal você implementar isso ????

3- Definir uma novo método CreateCommand no arquivo AcessoDados.vb para criar um comando do tipo Texto

'Cria um commando

Public Shared Function CreateCommand(ByVal sql As String) As DbCommand

Try

   Dim dbProviderName As String = Configuracao.DbProviderName

   Dim dbConnectionString As String = Configuracao.DbConnectionString

   Dim factory As DbProviderFactory = DbProviderFactories.GetFactory(dbProviderName)

   Dim connection As DbConnection = factory.CreateConnection()

   connection.ConnectionString = dbConnectionString

   Dim command As DbCommand = connection.CreateCommand()

   command.CommandType = CommandType.Text

   command.CommandText = sql

   Return command

 Catch ex As Exception

   Throw ex

End Try

End Function

O novo método recebe uma string chamada sql e define o tipo do comando como sendo CommandType.Text.

O comando SQL passando como parâmetro será o comando SQL a ser executado pelo objeto Command.

4- Definir um novo  método na classe Cliente.vb que irá receber o comando SQL

Imports System.Data

Imports System.Data.Common
 

Public Class Cliente


   Public Shared Function GetClientes() As DataTable

     Dim command As DbCommand = AcessoDados.CreateCommand()

     command.CommandText = "GetClientes"

     Return AcessoDados.ExecuteReader(command)

  End Function


   Public
Shared Function GetProdutos(ByVal sql As String) As DataTable

     Dim command As DbCommand = AcessoDados.CreateCommand(sql)

      command.CommandText = sql

      Return AcessoDados.ExecuteReader(command)

   End Function

End Class

Criei o método GetProdutos que recebe o comando SQL e chama o método CreateCommand para criar e executar o comando SQL.

5- Realizar a nova chamada na interface

Public Class _Default

Inherits System.Web.UI.Page

 

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

   'gdvClientes.DataSource = Cliente.GetClientes()

   gdvClientes.DataSource = Cliente.GetProdutos("Select top 10 productID,ProductName, UnitPrice from Products")

   gdvClientes.DataBind()

End Sub

End Class

 

No evento Load da página estou chamando o método GetProdutos passando o comando SQL para exibir os 10 produtos da tabela Products.

Executando o projeto teremos o seguinte resultado:

Dessa forma quis mostrar as possibilidades de poder mudar o banco de dados sem ter que fazer grandes mudanças no projeto. Você pode melhorar ainda mais o exemplo tornando a aplicação totalmente customizada para acessar qualquer banco de dados.

Pegue o projeto completo aqui: (Versão VB .NET)  ASPNET_3CamadasVB.zip  

Obs: Este artigo é a versão para VB .NET do artigo: C# - Criando uma aplicação ASP .NET em 3 Camadas

"E Jesus lhes disse: Eu sou o pão da vida: aquele que vem a mim não terá fome; e quem crê em mim nunca terá sede." (João 6:35)

Referências:


José Carlos Macoratti