Migrando de ASP para ASP.NET

Com a vinda do ASP.NET e o Visual Studio .NET, quem utiliza o ASP para o desenvolvimento de aplicações Web sentiu e sente dificuldades para tal migração, principalmente com o novo conceito de Code Behind que tem por finalidade de separar o código que é executado no servidor do HTML que é exibido no cliente.

Muitas vezes chegam até a pensar se é viável ou não a migração. E a resposta é sim. O ASP.NET nos traz uma nova forma de desenvolvimento para a Web, possibilitando construirmos aplicativos profissionais com uma grande facilidade, principalmente quando utilizamos o Visual Studio .NET como ferramenta de desenvolvimento.

Este artigo tem como finalidade mostrar aos desenvolvedores ASP como são realizados os mais frequentes processos, fazendo uma comparação entre ASP e depois em ASP.NET, iniciando com um overview sobre a plataforma .NET.

.NET Framework

O Microsoft .NET Framework é um conjunto de objetos para a construção de aplicativos, sejam eles Web, Windows ou Mobile. Atualmente ele se encontra em sua versão 1.1, e qual podemos utilizar o Visual Studio .NET 2003 para desenvolvemos sob ela.

CLR – Common Language Runtime

O Common Language Runtime (CLR) é o ambiente que gerencia a execução de código. Tradicionalmente ao criar um aplicativo, (em Visual Basic por exemplo), o mesmo é compilado em linguagem que o computador possa entender (0 e 1) e então o executa. Note que em diferentes tipos de computadores (PC’s e Machintoshes), você deverá recompilar o aplicativo para o mesmo se adaptar ao computador que vai utilizá-lo. Com a .NET Framework, isso funciona de forma diferente.

Em .NET Framework você utiliza uma linguagem de programação (sendo Visual Basic .NET ou Visual C# .NET) para escrever o código e a .NET Framework em conjunto com a CLR para compilar este código escrito. Mas ao invés deste código ser compilado para a linguagem nativa do computador, o mesmo é compilado para uma linguagem intermediária, chamada de MSIL (Microsoft Intermediate Language), que é uma forma abreviada de representar este código que você escreveu.

Tendo este código intermediário, ao executar o aplicativo o Common Language Runtime assume e compila o código, agora em linguagem nativa do computador por um compilador Just-In-Time (JIT), otimizando o melhor possível para aquele processador. Veremos abaixo as duas formas, com e sem o .NET Framework:

Figura 1 – Aplicativo sendo executado da forma tradicional.

 


Figura 2 – Com o .NET Framework.

Metadados

Quando compilamos nossos aplicativos ASP.NET, eles também são compilados para MSIL, criando assim o que chamamos de metadados que são informações descritivas sobre o aplicativo, dizendo o que o aplicativo pode fazer, a que pertence, etc.

A CLR utiliza esses metadados para descobrir de que forma executar esse aplicativo. Esse código que é executado pela CLR, é o que chamamos de código gerenciado. Isso faz com que o desenvolvedor não precise construir manulmente para gerenciar os recursos. Mas isso não é tudo que a CLR faz. Além disso, nos fornece a integração entre diferentes linguagens, tratamento de erros, entre outras características importantes para o desenvolvimento de nossas aplicações (Windows, Web ou Mobile).

Diferenças do ASP.NET em relação ao ASP

Entre os muitos benefícios fornecidos pelo ASP.NET tais como cache, compilação de código, segurança podemos destacar a facilidade no desenvolvimento, pois como vimos anteriormente, o código fica encapsulado dentro de um arquivo *.DLL, qual é preciso apenas utilizar o XCOPY para a distribuição, não havendo a necessidade do registro da mesma com o uso do REGSVR32.EXE, não tendo mais o “DLL Hell” (Inferno das DLL’s).

No ASP tinhamos o código que era executado dentro das tags <% … %> que atualmente não é mais compilado e seu uso não aconselhado, pois evita a mescla de código de servidor juntamente com o código HTML, o chamado spaghetti code.

Uma das grandes inovações é o CodeBehind. Com ele é possível separarmos o código do servidor do código HTML. O CodeBehind pode ser escrito em Visual Basic .NET ou Visual C# .NET e ao compilar o aplicativo esse código é encapsulado dentro da DLL, sendo necessário apenas o envio do arquivo ASPX para o servidor de produção. Ao criar um novo WebForm no Visual Studio .NET, são criados dois arquivos: o arquivo Arquivo.aspx (arquivo que contém o código HTML) e o Arquivo.aspx.vb ou Arquivo.aspx.cs (arquivo que contém o código que é executado no servidor). Quando o aplicativo é escrito em Visual Basic .NET, a extensão do arquivo é *.aspx.vb e sendo escrito em Visual C# .NET, a extensão será *.aspx.cs.

Abaixo veremos a estrutura do CodeBehind:

Figura 3 – Estrutura do CodeBehind dos arquivos ASPX.

O Fluxo

Poderão notar na primeira vez que executar o aplicativo, haverá um leve retardo. Isso ocorre devido a compilação do código que é realizado. Já na segunda vez esse processo não é efetuado, aumentando ainda mais a performance do aplicativo. Ao receber a solicitação de uma página, a mesma é compilada (caso seja a primeira vez), trata os eventos da Página e de seus controles, executa o código referente à esses eventos e finalmente gera o código HTML e envia ao browser. Abaixo a imagem ilustra o processo.

Figura 4 – Processo de execução de uma página ASPX.

As Linguagens de Programação

Vale lembrar que ASP assim como o ASP.NET não é uma linguagem de programação e sim uma tecnologia para desenvolvimento de aplicativos Web-Based. com isso, temos algumas linguagens em quais podemos escrever aplicativos ASP.NET, tais como: Visual Basic .NET, Visual C# .NET, C++ ou JScript.NET, que independentemente de qualquer linguagem que escrevemos, o código será sempre compilado para MSIL. Essas linguagens estão em conformidade com a CLS – Common Language Specification, que garante a conversação de aplicativos de diferentes linguagens. E todas as linguagens devendo ser 100% Orientada a Objetos.

Em ASP utilizavamos VBScript ou JavaScript para escrevemos os aplicativos, sendo os mesmos interpretados quando eram executados.

Hoje temos linguagens fortemente tipadas para isso, ou seja, por padrão devemos sempre especificar qual o tipo da variável qual estamos trabalhando, nos obrigando a declarar todas as váriveis.

Comparando ASP vs. ASP.NET (Códigos)

Abaixo será mostrado uma série de exemplos feitos em ASP e depois em ASP.NET para mostrar a diferença entre as duas tecnologias. Com esses exemplos ficará claro a facilidade de desenvolvimento de aplicativos feitos em ASP.NET.

Preenchendo DropDownList

:: ASP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 
Dim conn
Dim rs
 
Set rs = Server.CreateObject(“ADODB.Recordset”)
conn.Open
rs.Open “SELECT * FROM Categories”,conn
If Not rs.EOF Then
    Response.Write (“<select name = ‘cboareas’>”)
    Response.Write (“<option value = ”>Selecione…</option>”)
    While Not rs.EOF
        Response.Write (“<option value = ” & rs(“CategoryID”))
        Response.Write (“>” & rs(“CategoryName”) & “</option>”)
        rs.Movenext
    Wend
    Response.Write (“</select>”)
End If
rs.Close
conn.Close
 
Set rs = Nothing
Set conn = Nothing
 

 

:: ASP.NET
1
2
3
4
5
6
7
8
9
 
Dim conn As SqlConnection = New SqlConnection(“CONNECTION_STRING”)
Dim cmd As SqlCommand = New SqlCommand(“SELECT * FROM Categories”, conn)
 
Me.DropDownList1.DataTextField = “CategoryName”
Me.DropDownList1.DataValueField = “CategoryID”
conn.Open()
Me.DropDownList1.DataSource = cmd.ExecuteReader
Me.DropDownList1.DataBind()
conn.Close()
 

Exibindo Grid’s de dados

:: ASP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 
Dim conn
Dim rs
 
Set rs = Server.CreateObject(“ADODB.Recordset”)
conn.Open
rs.Open “SELECT * FROM Categories”,conn
If Not rs.EOF Then
    Response.Write (“<table width = ‘100%’ align = ‘center’>”)
    While Not rs.EOF
        Response.Write (“<tr>”)
        Response.Write (“<td>” & rs(“CategoryID”) & “</tr>”)
        Response.Write (“<td>” & rs(“CategoryName”) & “</tr>”)
        Response.Write (“</tr>”)
        rs.Movenext
    Wend
    Response.Write (“</table>”)
End If
rs.Close
conn.Close
 
Set rs = Nothing
Set conn = Nothing
 

 

:: ASP.NET
1
2
3
4
5
6
7
 
Dim conn As SqlConnection = New SqlConnection(“CONNECTION_STRING”)
Dim cmd As SqlCommand = New SqlCommand(“SELECT * FROM Categories”, conn)
 
conn.Open()
Me.DataGrid1.DataSource = cmd.ExecuteReader
Me.DataGrid1.DataBind()
conn.Close()
 

Formulários – Post

:: ASP
1
 
Response.Write(Request.Form(“TextBox1”))
 

 

:: ASP.NET
1
2
3
4
 
Private Sub Button1_Click(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles Button1.Click
    Response.Write(Me.TextBox1.Text)
End Sub
 

OBS.: Como o desenvolvimento de aplicações ASP.NET esta muito semelhante à aplicações Windows, agora basta darmos um duplo clique no botão e ali codificar, não havendo mais a necessidade da criação de uma nova página para processar o formulário.

Acesso à Banco de Dados

:: ASP
1
2
3
4
5
6
7
8
 
Dim conn
 
Set conn = Server.CreateObject(“ADODB.Connection”)
conn.ConnectionString = “CONNECTION_STRING”
conn.Open()
    ‘…
conn.Close()
Set conn = Nothing
 

 

:: ASP.NET
1
2
3
4
 
Dim conn As SqlConnection = New SqlConnection(“CONNECTION_STRING”)
conn.Open()
    ‘…
conn.Close()
 

Preenchendo um Formulario

:: ASP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
 
Dim conn
Dim rs
 
Set rs = Server.CreateObject(“ADODB.Recordset”)
conn.Open
rs.Open “SELECT TOP 1 * FROM Categories”,conn
If Not rs.EOF Then
    Response.Write (“<input type = ‘text’ name = ‘txtNome’ value = ‘” & rs(“CategoryName”) & “‘>”)
End If
rs.Close
conn.Close
 
Set rs = Nothing
Set conn = Nothing
 

 

:: ASP.NET
1
2
3
4
5
6
7
8
9
10
 
Dim conn As SqlConnection = New SqlConnection(“CONNECTION_STRING”)
Dim cmd As SqlCommand = New SqlCommand(“SELECT Top 1 * FROM Categories”, conn)
 
conn.Open()
Dim dr As SqlDataReader = cmd.ExecuteReader
 
If dr.Read() Then
    Me.txtNome.Text = dr(“CategoryName”)
End If
conn.Close()
 

Lendo o conteudo de Arquivos TXT

:: ASP
1
2
3
4
5
6
7
 
Dim txt
 
Set txt = FSO.OpenTextFile(Server.MapPath(“Arquivo.txt”))
Do While txt.AtendOfStream <> True
    Response.Write(txt.ReadLine)
Loop
txt.Close
 

 

:: ASP.NET
1
2
3
 
Dim reader As New StreamReader(Server.MapPath(“Arquivo.txt”))
Dim conteudo As String = reader.ReadToEnd
Response.Write(conteudo)
 

Observações Importantes: Como nos exemplos acima utilizamos como Base de Dados o SQL Server 2000, deve se importar o Namespace System.Data.SqlClient. Ja para utilizar as classes para manipulação de arquivos, deve se importar o Namespace System.IO (Somente para os exemplos escritos em ASP.NET). Abaixo a sintaxe para a Importação:

1
2
 
Imports System.Data.SqlClient
Imports System.IO
 

Conclusão: Como vimos o ASP.NET nos fornece uma facilidade muito grande. Utilizando ainda o Visual Studio .NET como ferramenta de desenvolvimento, as coisas ficam ainda mais fáceis, visto que temos Wizards, Intellisense, entre outras ferramentas que proporcionam um desenvolvimento rápido de aplicações.

Paginando dados com DataList

O grande problema, é que retornamos ao cliente registros indispensáveis para página corrente, o que de certa forma, causa um grande tráfego na rede para no final ser desconsiderado. Sendo assim, retornar todos os registros, e armazenar em uma variável de sessão, também é muito custoso, talvez quando o acesso é mínimo, não se perceba, mas quando a quantidade de usuários requisitando a mesma informação, isso poderá ocasionar sérios problemas de performance.

Tendo este cenário e/ou problema, a solução seria retornarmos da base de dados somente os registros correspondentes a página qual o usuário requerer. Além de diminuir o tráfego de dados na rede, isso nos proporcionará um grande ganho de performance. O artigo mostrará como retornar somente os registros da base de dados qual se enquadram com a página que o usuário requerer. Isso será feito através de uma Stored Procedure, utilizando a tabela Customers da base de dados Northwind como exemplo. Através de um SqlDataReader, recuperamos o result set retornado pela Stored Procedure e populamos o controle DataList.

O primeiro passo e construirmos a Stored Procedure para nos retornar os registros que necessitamos. Com isso, precisamos informar a ela a pagina requerida pelo Usuário, a quantidade de registros à ser exibido por página e também criarmos um parâmetro de OUTPUT para sabermos a quantidade total de registros, que é necessário para efetuar os cálculos no cliente, para que seja possível manipular corretamente a navegação entre as páginas. Abaixo a Stored Procedure responsável por devolver apenas os registros que necessitamos:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
 
CREATE PROCEDURE ResgatarClientes
 
    @QtdePagina As Int,
    @PagAtual As Int,
    @TotalClientes As Int OUTPUT
 
    AS
 
    DECLARE @ContactName As Varchar(50)
    DECLARE @City As Varchar(50)
    DECLARE @QtdeInicial As Int
    DECLARE @Contador As Int
 
    SET @QtdeInicial = 0
    SET @Contador = 0
 
    SET NOCOUNT ON
 
    CREATE TABLE #ClientesTemp
    (
        ContactName Varchar(50)
        City Varchar(50)
    )
 
    DECLARE curPaginacaoClientes CURSOR FAST_FORWARD FOR
        SELECT ContactName, City FROM Customers ORDER BY ContactNameASC
 
    OPEN curPaginacaoClientes
    FETCH NEXT FROM curPaginacaoClientes
        INTO @ContactName, @City
 
        WHILE @@FETCH_STATUS = 0
        BEGIN
            IF @QtdeInicial >= (@PagAtual * @QtdePagina) – @QtdePagina
            BEGIN
                INSERT INTO #ClientesTemp VALUES(@ContactName, @City)
                SET @Contador = @Contador + 1
 
                IF @Contador >= @QtdePagina
                    BREAK
            END
            SET @QtdeInicial = @QtdeInicial + 1
 
            FETCH NEXT FROM curPaginacaoClientes
               INTO @ContactName, @City
        END
 
    CLOSE curPaginacaoClientes
    DEALLOCATE curPaginacaoClientes
 
    SELECT ContactName, City FROM #ClientesTemp
 
    DROP TABLE #ClientesTemp
 
    SET NOCOUNT OFF
 
    SET @TotalClientes = (SELECT COUNT(CustomerID) FROM Customers)
GO
 
Código 1 – Stored Procedure “ResgataClientes”.

Como vemos no código acima, a Stored Procedure recebe dois parâmetros que é a página requisitada pelo Usuário e a quantidade de registros por página. Além disso, como dito anteriormente, existe um parâmetro de OUTPUT chamado @TotalClientes que e responsável por retornar a quantidade de Clientes para que seja possível efetuar os cálculos e assim exibindo corretamente a navegação da paginação.

Podemos ver também que é criado uma tabela temporária na linha 19, chamada #ClientesTemp, que é utilizada posteriormente, sendo populada com os registros necessários. Depois disso é criado um Cursor na linha 25 e através dele percorremos a tabela Customers e preenchemos a tabela temporária, anteriormente criada. Feito isso, fechamos o Cursor e o retiramos da memória, e retornamos ao cliente o resultado de um SELECT efetuado nesta tabela temporária na linha 51 e depois apagamos esta tabela (linha 53). E finalmente, apenas atribuimos ao parâmetro de saída a quantidade de registros da tabela Customers na linha 57.

Ainda é possível testá-la no Query Analyser, através do seguinte código:

1
2
3
 
DECLARE @TotalRegistros As Int
EXECUTE ResgatarClientes 10, [N], @TotalClientes = @TotalRegistros OUTPUT
PRINT @TotalRegistros
 
Código 2 – Testando a Stored Procedure “ResgataClientes” no Query Analyser.

Como vemos no código acima, o número 10 é a quantidade de registros por página e o [N] refere-se a página que o cliente está requerendo.

Feito isso, o próximo passo é partir para a aplicação ASP.NET, que irá utilizar esta Stored Procedure para popular e paginar os dados em um controle do tipo DataList. Devemos apenas arrastar em nosso WebForm o DataList e quatro controles do tipo LinkButton, que serão responsáveis pela navegação do usuário. Vamos incluir em nosso WebForm um Data Member que será responsável por armazenar a quantidade de registros por páginas:

1
 
Private _totalRegistrosPagina As Integer = 10
 
Código 3 – Definindo através de um Data Member a quantidade de registros por página.

Logo, temos que criar um procedimento que será responsável por popular o DataList. Esta função se chamará CarregaGrid, e terá como parâmetro um valor inteiro representando a página que o usuário está requerendo. Vejamos abaixo o código deste procedimento:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
 
Private Sub CarregaGrid(ByVal paginaAtual As Integer)
    Dim conn As New SqlConnection(“CONNECTION_STRING”)
    Dim dr As SqlDataReader
    Dim cmd As New SqlCommand(“ResgatarClientes”, conn)
    cmd.CommandType = CommandType.StoredProcedure
 
    Dim paramQtdeRegistroPagina As SqlParameter
    paramQtdeRegistroPagina = New SqlParameter(“@QtdePagina”, SqlDbType.Int)
    paramQtdeRegistroPagina.Value = Me._totalRegistrosPagina
    cmd.Parameters.Add(paramQtdeRegistroPagina)
 
    Dim paramPaginaAtual As SqlParameter
    paramPaginaAtual = New SqlParameter(“@PagAtual”, SqlDbType.Int)
    paramPaginaAtual.Value = paginaAtual
    cmd.Parameters.Add(paramPaginaAtual)
 
    Dim paramTotalRegistros As SqlParameter
    paramTotalRegistros = New SqlParameter(“@TotalClientes”, SqlDbType.Int)
    paramTotalRegistros.Direction = ParameterDirection.Output
    cmd.Parameters.Add(paramTotalRegistros)
 
    Try
        conn.Open()
        dr = cmd.ExecuteReader(CommandBehavior.CloseConnection)
        If dr.HasRows() Then
            With Me.dtlDados
                .DataSource = dr
                .DataBind()
            End With
            Me.lblPaginaCorrente.Text = paginaAtual
        End If
    Catch ex As Exception
        Response.Write(ex.ToString)
    Finally
        If Not (dr Is Nothing) Then
            dr.Close()
        End If
        Call Me.ControlePaginacao(cmd.Parameters(“@TotalClientes”).Value)
    End Try
End Sub
 
Código 4 – Procedimento CarregaGrid().

Analisando o código acima, criamos os parâmetros referente à quantidade de registros por página e a página requerida pelo Usuário e também definimos o parâmetro de OUTPUT chamado @TotalClientes, qual retorna a quantidade total de registros. Depois disso, verificamos se é retornado algum registro através da propriedade HasRows(), que retorna True, caso encontrado algum registro, e com isso populamos o DataList com este DataReader, e depois de fechado o DataReader, recuperamos o valor do parâmetro OUTPUT e invocamos o procedimento ControlePaginacao, que é responsável por exibir a quantidade de páginas e a página atual para o Usuário.

O procedimento ControlePaginacao recebe como parâmetro a quantidade total de Clientes, e baseado nisso, exibe a quantidade total de páginas e a página atual em que o Usuário se encontra:

1
2
3
4
5
6
7
 
Private Sub ControlePaginacao(ByVal totalClientes As Integer)
    If (totalClientes Mod Me._totalRegistrosPagina) = 0 Then
        Me.lblTotal.Text = totalClientes / Me._totalRegistrosPagina
    Else
        Me.lblTotal.Text = Convert.ToInt32((totalClientes / Me._totalRegistrosPagina) + 1)
    End If
End Sub
 
Código 5 – Procedimento ControlePaginacao.

Agora, no evento Page_Load do WebForm, devemos chamar o procedimento CarregaGrid, passando como parâmetro o número 1, que refere-se a primeira página, lembrando que devemos chamar este procedimento quando não for PostBack. O código abaixo ilustra isso:

1
2
3
4
5
6
 
Private Sub Page_Load(…) Handles MyBase.Load
    If Not Page.IsPostBack Then
        Call Me.CarregaGrid(1)
        Call Me.Navegacao(1)
    End If
End Sub
 
Código 6 – Evento Page_Load do WebForm.

Ainda temos mais um procedimento para criar, chamado Navegacao, procedimento qual se encarrega de habilitar/desabilitar os botões de navegação da paginação. Este procedimento também é baseado na página atual que está sendo exibida. Vejamos abaixo o código deste procedimento na íntegra:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 
Private Sub Page_Load(ByVal paginaAtual As Integer)
    If paginaAtual = 1 Then
        With Me
            .lnkAnterior.Enabled = False
            .lnkProxima.Enabled = True
            .lnkPrimeiraPagina.Enabled = False
            .lnkUltimaPagina.Enabled = True
        End With
    ElseIf paginaAtual = Me.lblTotal.Text AndAlso paginaAtual > 1 Then
        With Me
            .lnkAnterior.Enabled = True
            .lnkProxima.Enabled = False
            .lnkPrimeiraPagina.Enabled = True
            .lnkUltimaPagina.Enabled = False
        End With
    Else
        With Me
            .lnkAnterior.Enabled = True
            .lnkProxima.Enabled = True
            .lnkPrimeiraPagina.Enabled = True
            .lnkUltimaPagina.Enabled = True
        End With
    End If
End Sub
 
Código 7 – Procedimento Navegacao.

Depois disso, nosso controle ficará semelhante à imagem abaixo:

Figura 1 – Controle DataList já com os controles de Navegação pelas páginas.

Mas ainda resta codificarmos os eventos Click() dos LinkButton responsáveis pela navegação das páginas. Temos quatro LinkButtons com as seguintes funcionalidades:

  • < – Primeira página.
  • << – Página anterior.
  • >> – Próxima página.
  • > – Última página.
1
2
3
4
 
Private Sub lnkPrimeiraPagina_Click(…) Handles lnkPrimeiraPagina.Click
    Call Me.CarregaGrid(1)
    Call Me.Navegacao(1)
End Sub
 
Código 8 – Procedimento que retorna à primeira página.

 

1
2
3
4
 
Private Sub lnkUltimaPagina_Click(…) Handles lnkUltimaPagina.Click
    Call Me.CarregaGrid(Convert.ToInt32(Me.lblTotal.Text))
    Call Me.Navegacao(Convert.ToInt32(Me.lblTotal.Text))
End Sub
 
Código 9 – Procedimento que vai para a última página.

 

1
2
3
4
5
 
Private Sub lnkAnterior_Click(…) Handles lnkAnterior.Click
    Dim paginaAtual As Integer = Integer.Parse(Me.lblPaginaCorrente.Text.ToString()) – 1
    Call Me.CarregaGrid(Convert.ToInt32(paginaAtual)
    Call Me.Navegacao(Convert.ToInt32(paginaAtual)
End Sub
 
Código 10 – Procedimento que retorna à página anterior.

 

1
2
3
4
5
 
Private Sub lnkProxima_Click(…) Handles lnkProxima.Click
    Dim paginaAtual As Integer = Integer.Parse(Me.lblPaginaCorrente.Text.ToString()) + 1
    Call Me.CarregaGrid(Convert.ToInt32(paginaAtual)
    Call Me.Navegacao(Convert.ToInt32(paginaAtual)
End Sub
 
Código 11 – Procedimento vai para a página posterior.

Conclusão: Vimos neste artigo como resgatar os dados da base de dados através de uma Stored Procedure, mas limitando os dados da página a ser exibida para proporcionar performance, retornando os dados para uma aplicação ASP.NET, e populando um controle DataList, controlando e exibindo a paginação.

PaginandoDadosStoredProcedure.zip (22.51 kb)

Disparando o Evento SelectedIndexChanged do DropDownList

Claro que somente isso não era/é necessário. A necessidade de utilizarmos DropDownList dentro do DataGrid é muito grande, o que exige um pouco de atenção para poder populá-lo. Mas nesse caso a dificuldade não é tão grande. O problema começa a aparecer quando há a necessidade de termos dois DropDownLists dentro deste DataGrid, mas um deles dependendo da seleção do primeiro, e baseado nisso popular este segundo DropDownList. Um cenário bastante conhecido: a exibição dos Clientes dentro deste DataGrid, visualizando a cidade e estado de residência deste Cliente, que ao clicar em editar, deve-se exibir dois DropDownList contendo o Estados e os Municípios que devem ser populados de acordo com o Estado selecionado.

Tendo este cenário, este artigo explicará como construir um DataGrid onde dentro dele, quando editarmos um determinado registro, a linha em edição deverá mostrar os DropDownLists (Estado e Município, respectivamente), onde ao selecionar o Estado, o segundo DropDownList deverá ser populado com as cidades referentes aquele Estado.

Depois de criado uma Aplicação do tipo ASP.NET Web Application, você deve adicionar um DataGrid ao seu WebForm. Com isso, vá até o Property Builder e desmarque a opção: “Create columns automatically at run time”. Com isso, basta adicionarmos o campos a serem exibidos no DataGrid e juntamente os botões de Editar e Cancelar. Finalmente você terá o teu DataGrid próximo à Figura 1 (abaixo):

Figura 1DataGrid já formatado.

Depois de definido as colunas que serão apresentadas no DataGrid, devemos formatar agora o modo de edição do mesmo. Para isso, clique com botão direito do mouse em cima do DataGrid, e na opção Edit Template, selecione a coluna Estado. Com o Template em edição, você adiciona um DropDownList no EditItemTemplate chamado “cboEstado”. Repita os passos anteriores para a coluna Cidade. A Figura 2 (abaixo) ilustra o processo:

Figura 2 – Configurando o EditItemTemplate.

Com o design do DataGrid pronto, resta agora começarmos a codificar o WebForm para popular o DataGrid, mas inicialmente vou chamar a atenção para o código abaixo:

1
2
3
4
5
6
 
Public Class _Default
 
    Private _estado As String
    Private _cidade As String
 
End Class
 
Código 1 – Membros da Classe.

Como podemos ver, é criado estes dois Data Members que serão utilizados posteriormente para quando o Usuário desejar editar o registro, ficar armazenado nestes membros o Estado e Cidade do registro à ser editado, para que seja possível após a carga nos DropDownLists, posicionar os Items de acordo com a Cidade e Estado atual do Cliente.

O método abaixo (CarregaGrid()) é utilizado para preencher o DataGrid no evento Load do WebForm. Está densvinculado, pois será necessário chamarmos em diversos locais. Vejamos:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 
Private Sub Page_Load(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles MyBase.Load
 
    If Not Page.IsPostBack Then
        Call Me.CarregaGrid()
    End If
End Sub
 
Private Sub CarregaGrid()
    Dim conn As New SqlConnection(“CONNECTION_STRING”)
    Dim cmd As New SqlCommand(“SELECT * FROM [User] ORDER BY Nome ASC”, conn)
    Try
        conn.Open()
        With Me.dg
            .DataSource = cmd.ExecuteReader()
            .DataBind()
        End With
    Catch ex As Exception
        Response.Write(ex.ToString)
    Finally
        If Not conn.State = ConnectionState.Closed Then
            conn.Close()
        End If
    End Try
End Sub
 
Código 2 – Método para carregar o DataGrid.

Como vemos acima, no evento Load do WebForm, chamamos a função CarregaGrid() quando não for um PostBack. Utilizando o SqlDataReader, resgatamos os registros da tabela “Users” e popularmos o DataGrid. Como já definimos as colunas a serem apresentadas, a exibição é controlada pelo DataGrid.

Com o DataGrid já preenchido, devemos codificar os eventos EditCommand e CancelCommand do DataGrid, para que quando o Usuário optar por editar uma determinada linha/registro do DataGrid, puder transformá-la, colocando a disposição os DropDownLists de Estado e Cidade. Abaixo o código para isso:

1
2
3
4
5
6
7
8
 
Private Sub dg_EditCommand(ByVal source As System.Object, _
    ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs) Handles dg.EditCommand
 
    Me._cidade = DirectCast(e.Item.FindControl(“Label1”), Label).Text
    Me._estado = DirectCast(e.Item.FindControl(“Label2”), Label).Text
    Me.dg.EditItemIndex = e.Item.ItemIndex
    Call Me.CarregaGrid()
End Sub
 
Código 3 – Evento EditCommand do DataGrid.

Vemos que no evento EditCommand, qual ocorre sempre que o Usuário desejar editar algum registro do DataGrid, armazenamos nos nossos Data Members (falado acima) os valores atuais do Estado e da Cidade do Cliente, que estão armazenados nos Labels. Abaixo o evento CancelCommand do DataGrid, necessário para quando o Usuário desejar cancelar a edição o DataGrid voltar à sua posição inicial:

1
2
3
4
5
6
7
 
Private Sub dg_CancelCommand(ByVal source As System.Object, _
    ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs) _
    Handles dg.CancelCommand
 
    Me.dg.EditItemIndex = –1
    Call Me.CarregaGrid()
End Sub
 
Código 4 – Evento CancelCommand do DataGrid.

Depois dessas funcionalidades codificadas, temos que criar os métodos que serão responsáveis por popular os DropDownLists. Veremos abaixo o método CarregaEstado() que retorna um ArrayList contendo os Estados que serão inseridos no DropDownList Estado dentro do DataGrid:

1
2
3
4
5
6
7
8
9
 
Private Function CarregaEstado() As ArrayList
    Dim arr As New ArrayList
    With arr
        .Add(String.Empty)
        .Add(“SP”)
        .Add(“MT”)
    End With
    Return arr
End Function
 
Código 5 – Método para carregar o DropDownList Estado.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 
Private Sub PopulaCidades(ByVal drop As DropDownList, _
    ByVal cidadeAtual As String, ByVal estado As String)
 
    Select Case estado
        Case “SP”
            With drop.Items
                .Add(“Valinhos”)
                .Add(“São Paulo”)
                .Add(“Campinas”)
            End With
        Case “MT”
            With drop.Items
                .Add(“Rondonópolis”)
                .Add(“Cuiabá”)
                .Add(“Várzea Grande”)
            End With
    End Select
    drop.SelectedIndex = drop.Items.IndexOf(drop.Items.FindByText(cidadeAtual))
End Sub
 
Código 6 – Método para carregar o DropDownList Cidade.

O método PopulaCidades(…) acima, recebe por parâmetro o DropDownList que será carregado com as cidades, a cidade atual para que possamos selecionar (marcarmos) a mesma dentro do DropDownList depois de carregado e finalmente o estado para poder fazer a busca de acordo com a seleção do Usuário.

Agora será necessário codificarmos dois eventos do DataGrid: ItemDataBound e ItemCreated. O evento ItemCreated é disparado quando um controle é criado no DataGrid. Já o evento ItemDataBound é disparado logo após que um Item é inserido no cliente. Utilizaremos o evento ItemCreated para quando o DataGrid estiver com algum Item sendo editado, o mesmo possa atribuir ao DropDownList de Estado uma função para ser disparada quando ocorrer o evento SelectedIndexChanged do mesmo. Vejamos abaixo como ficará este evento:

1
2
3
4
5
6
7
8
9
10
11
12
 
Private Sub dg_ItemCreated(ByVal source As System.Object, _
    ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs) Handles dg.ItemCreated
 
    If e.Item.ItemType = ListItemType.EditItem Then
        With DirectCast(e.Item.FindControl(“cboEstado”), DropDownList)
            .DataSource = .CarregaEstado()
            .DataBind()
        End With
        AddHandler DirectCast(e.Item.FindControl(“cboEstado”), DropDownList).SelectedIndexChanged, _
        AddressOf Me.CarregaCidade
    End If
End Sub
 
Código 7 – Evento ItemCreated do DataGrid.

Como vemos no evento ItemCreated logo acima, ao encontrar o DropDownList de Estado, já o populamos com o retorno da função CarregaEstado(), e em seguida utilizamos o AddHandler para que quando o evento SelectedIndexChanged deste DropDownList for disparado, executar a função chamada: CarregaCidade(…). Esta função deverá ter obrigatoriamente a mesma assinatura do evento SelectedIndexChanged. Veremos abaixo ela em detalhes:

1
2
3
4
5
6
7
 
Private Sub CarregaCidade(ByVal sender As Object, ByVal e As EventArgs)
    Dim drop As DropDownList = DirectCast(sender, DropDownList)
    Dim dgi As DataGridItem = drop.Parent.Parent
    Dim drop2 As DropDownList = DirectCast(dgi.FindControl(“cboCidade”), DropDownList)
    drop2.Items.Clear()
    Call Me.PopulaCidades(drop2, drop2.SelectedValue, drop.SelectedValue)
End Sub
 
Código 8 – Método que será disparado quando o DropDownList Estado for alterado.

Analisando o código acima, criamos três objetos: drop, dgi e drop2. O drop resgata a referência do objeto que como parâmetro através do sender. Já o dgi, recuperamos a referência do controle pai do drop na hierarquia de controles da página. Com isso, conseguimos saber em qual Item do DataGrid ele se encontra. E finalmente, como temos o Item do DataGrid, basta utilizarmos o método FindControl para popularmos o DropDownList com as cidades.

Para finalizar, apenas resta codificarmos o evento ItemDataBound do DataGrid qual utilizaremos para quando o Usuário desejar editar algum Item, os DropDownLists de Estado e Cidade já vieram populados de acordo com registro atual do Cliente na Base de Dados, ou seja, se o Cliente pertencer ao Estado de “SP”, o DropDownList de Cidade já deverá conter as cidades pertencentes à este Estado.

Depois de todos estes passos, o resultado será:

Figura 3 – Ao clicar em Editar, os DropDownLists já aparecem carregados corretamente.

 

Figura 4 – Repare que a Cidade e Estado estão “marcados” de acordo com o Registro atual.

 

Figura 5 – Ao selecionar o Estado, o DropDownList é carregado de acordo com o Estado selecionado.

Conclusão: Vemos que o WebControl DataGrid nos fornece uma grande facilidade no desenvolvimento. Neste caso, utilizando DropDownLists e executando seu o evento SelectedIndexChanged precisamos codificar algumas linhas, mas nada complexo. Vimos neste artigo, um cenário bastante comum em nosso “dia-a-dia”, ficando aqui explicado como implementá-lo.

DataGridDropDown.zip (21.17 kb)

Migrando para ASP.NET 2.0

Aqui é mostrado um artigo bem interessante no que diz respeito a migração de ASP.NET 1.x para ASP.NET 2.0. Pelo que pude perceber em fóruns que participo, o maior impacto no ASP.NET 2.0 tem sido causado pelo novo modelo de compilação que o mesmo, por default, cria múltiplos assemblies (arquivos *.dll) e desaparece com a pasta bin.

Unificando o Gerenciamento de Credenciais

Juval Lowy escreveu um artigo muito interessante explicando como unificar o gerenciamento de credenciais entre aplicações Windows Forms e ASP.NET neste endereço.

Como sabem, o .NET Framework 2.0 nos fornece uma infraestrutra para gerenciamento de credenciais/usuários através do que chamamos de MembershipProvider. O artigo define um Web Service para poder “compartilhar” com aplicações Windows Forms esta mesma infraestrutura. Abaixo o design da solução:

Url Mappings

Na versão anterior do ASP.NET, para conseguirmos termos uma espécie de “alias” para determinadas Urls de nossas aplicações. Isso é interessante para que o usuário não tenha que lembrar todo o path até uma determinada seção do web site (incluindo possíveis QueryStrings).

Neste caso, tínhamos que criar um módulo (que implementa a interface IHttpModule) e assim reescreve-las. Um exemplo que costumo citar como referencia, é o que Scott Mitchell escreveu aqui, no MSDN.com.

Agora, no ASP.NET 2.0, temos esta funcionalidade já instrinsica, e podemos utilizá-la, apenas colocando no arquivo Web.Config da aplicação a Url original e o “Alias”. Exemplo:

     <urlMappings enabled=”true”>
          <add url=”~/Artigos.aspx” mappedUrl=”~/Conteudo.aspx?Controle=Articles”/>
     </urlMappings>

O interessante é ver seu funcionamento, ou seja, dentro da classe HttpApplication, temos uma Friend Class chamada UrlMappingsExecutionStep, que por sua vez implementa a interface IExecutionStep, que contém um método chamado Execute. Este método, que também está implementado na classe UrlMappingsExecutionStep, recupera os mapeamentos feitos no arquivo Web.Config e através do método RewritePath da classe HttpContext reescreve a Url.

Compilação ASP.NET 2.0

Navegando pela internet, encontrei uma UI (User Inteface) para o utilitário “aspnet_compiler.exe”. Ela pode ser adquirida gratuitamente neste endereço: http://www.west-wind.com/tools/aspnetcompiler.asp

Outro post que me chamou a atenção foi o que Scott Allen fez aqui. Ele fala dos diversos arquivos *.dll que são criados na pré-compilação do ASP.NET 2.0. Vejam o tópico “What’s In Your Bin Directory?” deste post.

AccessMembershipProvider

Há alguns dias alguém nos newsgroups do MSDN Brasil perguntou porque depois dele migrar para a versão Beta 2 do Visual Studio .NET 2005, o AccessMembershipProvider parou de funcionar. Como tenho máquinas distintas com as duas versões instaladas, realmente não temos o AccessMembershipProvider implementado na versão Beta 2.

A resposta é que ele foi removido desta versão, dando agora, somente suporte ao SqlMembershipProvider, que é voltado para um servidor SQL Server, pelo seguinte motivo:

The Access providers were removed from Beta 2 and RTM since the Microsoft Access engine is not always appropriate for applications that need to support many concurrent users running against moderately sized databases. Sql Server Express was chosen as the default provider implementation since it has sufficient headroom to address the growing data requirements of today’s websites.

Mas de qualquer forma, se ainda há alguém que precise (tanto do AccessMembershipProvider quanto do AccessProfileProvider), poderá conseguir nos Starter Kits neste endereço: http://go.microsoft.com/fwlink/?linkid=49646&clcid=0x409

Site counters, DynamicImage Control e Image Generation Service

Para quem gostou destas novas “features” do ASP.NET 2.0, já pode ir arrumando outro jeito de se fazer isso. Sim, elas foram removidas do ASP.NET 2.0, de acordo com as Features postponed for ASP.NET 2.0 Beta 2.

Entre eles, o que mais era interessante na minha opinião, eram os Site Counters, mas agora, toca-me a fazer algo manual se quiser controlar isso.