2. Uma breve introdução ao ASP.NET
Propomos aqui apresentar, por meio de alguns exemplos, os conceitos de ASP.NET que nos serão úteis no restante do documento. Esta introdução não permite compreender as sutilezas das interações cliente/servidor de uma aplicação web. Para isso, pode-se consultar:
- Programação ASP.NET [Desenvolvimento web com ASP.NET 1.1 (2004)]
Esta introdução destina-se àqueles que desejam avançar rapidamente, aceitando, em um primeiro momento, deixar de lado alguns pontos que podem ser importantes. A continuação do documento permite aprofundar esses pontos. Aqueles que já conhecem ASP.NET podem passar diretamente para o parágrafo 3.
2.1. Um projeto de exemplo
2.1.1. Criação do projeto
![]() |
- no [1], cria-se um novo projeto com o Visual Web Developer
- em [2], escolhe-se um projeto web em Visual C#
- em [3], indica-se que se deseja criar um aplicativo web ASP.NET
- em [4], dá-se um nome ao aplicativo. Será criada uma pasta para o projeto com esse nome.
- em [5], indica-se a pasta pai da pasta [4] do projeto
![]() |
- em [6], o projeto criado
- [Default.aspx] é uma página da web criada por padrão. Ela contém as tags HTML e as tags ASP.NET
- [Default.aspx.cs] contém o código de gerenciamento dos eventos provocados pelo usuário na página [Defaul.aspx] exibida em seu navegador
- [Default.aspx.designer.cs] contém a lista dos componentes ASP.NET da página [Default.aspx]. Cada componente ASP.NET inserido na página [Default.aspx] gera a declaração desse componente em [Default.aspx.designer.cs].
- [Web.config] é o arquivo de configuração do projeto ASP.NET.
- [References] é a lista dos DLL utilizados pelo projeto web. Esses DLL são bibliotecas de classes que o projeto precisa utilizar. Em [7] está a lista dos DLL definidos por padrão nas referências do projeto. A maioria delas é desnecessária. Se o projeto precisar utilizar uma DLL que não esteja listada em [7], ela pode ser adicionada por meio de [8].
2.1.2. A página [Default.aspx]
Se o projeto for executado por meio de [Ctrl-F5], a página [Default.aspx] será exibida em um navegador:
![]() |
- em [1], a página URL do projeto web. O Visual Web Developer possui um servidor web integrado que é iniciado quando se solicita a execução de um projeto. Ele escuta em uma porta aleatória, neste caso a 1490. A porta de escuta é normalmente a porta 80. No [1], nenhuma página é solicitada. Nesse caso, é exibida a página [Default.aspx], daí o nome de “página padrão”.
- Em [2], a página [Default.aspx] está vazia.
- No Visual Web Developer, a página [Default.aspx] [3] pode ser criada visualmente (aba [Design]) ou por meio de tags (aba [Source])
- em [4], a página [Defaul.aspx] no modo [Design]. Ela é criada ao arrastar e soltar componentes encontrados na caixa de ferramentas [5].
![]() |
O modo [Source] [6] permite acessar o código-fonte da página:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="Intro._Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
</div>
</form>
</body>
</html>
- a linha 1 é uma diretiva ASP.NET que lista algumas propriedades da página
- a diretiva Page se aplica a uma página da web. Existem outras diretivas, como Application, WebService, ... que se aplicam a outros objetos ASP.NET
- o atributo CodeBehind indica o arquivo que gerencia os eventos da página
- o atributo Language indica a linguagem .NET utilizada pelo arquivo CodeBehind
- o atributo Inherits indica o nome da classe definida dentro do arquivo CodeBehind
- O atributo AutoEventWireUp="true" indica que a associação entre um evento em [Default.aspx] e seu manipulador em [Defaul.aspx.cs] é feita por meio do nome do evento. Assim, oevento Load na página [Default.aspx] será processado pelo método Page_Load da classe Intro._Default, definida pelo atributo Inherits.
- as linhas 4 a 14 descrevem a página [Defaul.aspx] por meio de tags:
- HTML clássicas, como a tag <body> ou <div>
- ASP.NET. Essas são as tags que possuem o atributo runat="server". As tags ASP.NET são processadas pelo servidor web antes do envio da página ao cliente. Elas são transformadas em tags HTML. O navegador do cliente recebe, portanto, uma página HTML padrão, na qual não há mais tags ASP.NET.
A página [Default.aspx] pode ser modificada diretamente a partir de seu código-fonte. Às vezes, isso é mais simples do que passar pelo modo [Design]. Modificamos o código-fonte da seguinte maneira:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="Intro._Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Introduction ASP.NET</title>
</head>
<body>
<h3>Introduction à ASP.NET</h3>
<form id="form1" runat="server">
<div>
</div>
</form>
</body>
</html>
Na linha 6, atribuímos um título à página por meio da tag HTML <title>. Na linha 9, inserimos um texto no corpo (<body>) da página. Se executarmos o projeto (Ctrl-F5), obtemos o seguinte resultado no navegador:
![]() |
2.1.3. Os arquivos [Default.aspx.designer.cs] e [Default.aspx.cs]
O arquivo [Default.aspx.designer.cs] declara os componentes da página [Defaul.aspx]:
//------------------------------------------------------------------------------
// <gerado automaticamente>
// Este código foi gerado por uma ferramenta.
// Versão do runtime: 2.0.50727.3603
//
// As alterações feitas neste arquivo podem causar um comportamento incorreto e serão perdidas se
// o código for regenerado.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Intro {
public partial class _Default {
/// <summary>
/// Controle form1.
/// </summary>
/// <remarks>
/// Campo gerado automaticamente.
/// Para modificar, mova a declaração do campo do arquivo de design para o arquivo de código-backend.
/// </remarks>
protected global::System.Web.UI.HtmlControls.HtmlForm form1;
}
}
Nesse arquivo, encontra-se a lista dos componentes ASP.NET da página [Default.aspx] que possuem um identificador. Eles correspondem às tags de [Default.aspx] que possuem o atributo runat="server" e o atributo id. Assim, o componente da linha 23 acima corresponde à tag
<form id="form1" runat="server">
de [Default.aspx].
O desenvolvedor interage pouco com o arquivo [Default.aspx.designer.cs]. No entanto, esse arquivo é útil para identificar a classe de um componente específico. Assim, vemos abaixo que o componente form1 é do tipo HtmlForm. O desenvolvedor pode então explorar essa classe para conhecer suas propriedades e métodos. Os componentes da página [Default.aspx] são utilizados pela classe do arquivo [Default.aspx.cs]:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace Intro
{
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
}
}
Observe-se que a classe definida nos arquivos [Default.aspx.cs] e [Default.aspx.designer.cs] é a mesma (linha 10): Intro._Default. É a palavra-chave partial que permite estender a declaração de uma classe por vários arquivos, neste caso, dois.
Na linha 10, acima, vemos que a classe [_Default] estende a classe [Page] e herda seus eventos. Um deles é o evento Load, que ocorre quando a página é carregada pelo servidor web. Na linha 12, o método Page_Load que gerencia o evento Load da página. Geralmente é aqui que se inicializa a página antes de sua exibição no navegador do cliente. Aqui, o método Page_Load não faz nada.
A classe associada a uma página da web, neste caso a classe Intro._Default, é criada no início da solicitação do cliente e destruída quando a resposta ao cliente é enviada. Portanto, ela não pode ser usada para armazenar informações entre duas solicitações. Para isso, é necessário utilizar o conceito de sessão do usuário.
2.2. Os eventos de uma página da web ASP.NET
Criamos a seguinte página [Default.aspx]:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="Intro._Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Introduction ASP.NET</title>
</head>
<body>
<h3>Introduction à ASP.NET</h3>
<form id="form1" runat="server">
<div>
<table>
<tr>
<td>
Nom</td>
<td>
<asp:TextBox ID="TextBoxNom" runat="server"></asp:TextBox>
</td>
<td>
</td>
</tr>
<tr>
<td>
Age</td>
<td>
<asp:TextBox ID="TextBoxAge" runat="server"></asp:TextBox>
</td>
<td>
</td>
</tr>
</table>
</div>
<asp:Button ID="ButtonValider" runat="server" Text="Valider" />
<hr />
<p>
Evénements traités par le serveur</p>
<p>
<asp:ListBox ID="ListBoxEvts" runat="server"></asp:ListBox>
</p>
</form>
</body>
</html>
O modo [Design] da página é o seguinte:
![]() |
O arquivo [Default.aspx.designer.cs] é o seguinte:
namespace Intro {
public partial class _Default {
protected global::System.Web.UI.HtmlControls.HtmlForm form1;
protected global::System.Web.UI.WebControls.TextBox TextBoxNom;
protected global::System.Web.UI.WebControls.TextBox TextBoxAge;
protected global::System.Web.UI.WebControls.Button ButtonValider;
protected global::System.Web.UI.WebControls.ListBox ListBoxEvts;
}
}
Nele estão todos os componentes ASP.NET da página [Default.aspx] que possuem um identificador.
Atualizamos o arquivo [Default.aspx.cs] da seguinte forma:
using System;
namespace Intro
{
public partial class _Default : System.Web.UI.Page
{
protected void Page_Init(object sender, EventArgs e)
{
// observa-se o evento
ListBoxEvts.Items.Insert(0, string.Format("{0}: Page_Init", DateTime.Now.ToString("hh:mm:ss")));
}
protected void Page_Load(object sender, EventArgs e)
{
// registrando o evento
ListBoxEvts.Items.Insert(0, string.Format("{0}: Page_Load", DateTime.Now.ToString("hh:mm:ss")));
}
protected void ButtonValider_Click(object sender, EventArgs e)
{
// registra-se o evento
ListBoxEvts.Items.Insert(0, string.Format("{0}: ButtonValider_Click", DateTime.Now.ToString("hh:mm:ss")));
}
}
}
A classe [_Default] (linha 5) processa três eventos:
- o evento Init (linha 7), que ocorre quando a página é inicializada
- o evento Load (linha 13), que ocorre quando a página é carregada pelo servidor web. O evento Init ocorre antes do evento Load.
- o evento Click no botão ButtonValider (linha 19), que ocorre quando o usuário clica no botão [Valider]
O tratamento de cada um desses três eventos consiste em adicionar uma mensagem ao componente Listbox, denominado ListBoxEvts. Essa mensagem exibe a hora e o nome do evento. Cada mensagem é colocada no início da lista. Portanto, as mensagens localizadas no topo da lista são as mais recentes.
Ao executar o projeto, obtém-se a seguinte página:
![]() |
Pode-se observar em [1] que os eventos Page_Init e Page_Load ocorreram nessa ordem. Vale lembrar que o evento mais recente está no topo da lista. Quando o navegador solicita a página [Default.aspx] diretamente por meio de sua URL [2], ele o faz por meio de um comando HTTP (Protocolo de Transferência HyperText), chamado GET. Assim que a página for carregada no navegador, o usuário irá provocar eventos na página. Por exemplo, ele clicará no botão [Valider] [3]. Os eventos provocados pelo usuário, uma vez que a página tenha sido carregada no navegador, acionam uma solicitação à página [Default.aspx], mas, desta vez, com um comando HTTP chamado POST. Resumindo:
- o carregamento inicial de uma página P em um navegador é feito por uma operação HTTP GET
- os eventos que ocorrem em seguida na página geram, a cada vez, uma nova solicitação para a mesma página P, mas desta vez com o comando HTTP POST. É possível para uma página P saber se ela foi solicitada com um comando GET ou um comando POST, o que permite que ela se comporte de maneira diferente, se necessário — o que, na maioria das vezes, é o caso.
Solicitação inicial de uma página ASPX: GET
![]() |
- em [1], o navegador solicita a página ASPX por meio de um comando HTTP GET sem parâmetros.
- em [2], o servidor web envia como resposta o fluxo HTML, que é a tradução da página ASPX solicitada.
Processamento de um evento ocorrido na página exibida pelo navegador: POST
![]() |
- em [1], durante um evento na página HTML, o navegador solicita a página ASPX, já obtida por meio de uma operação GET, desta vez com um comando HTTP POST acompanhado de parâmetros. Esses parâmetros são os valores dos componentes que se encontram dentro da tag <form> da página HTML exibida pelo navegador. Esses valores são chamados de valores enviados pelo cliente. Eles serão utilizados pela página ASPX para processar a solicitação do cliente.
- Na página [2], o servidor web envia, em resposta, o fluxo HTML, que é a tradução da página ASPX solicitada inicialmente pela POST ou de outra página, caso tenha ocorrido uma transferência ou redirecionamento de página.
Voltemos à nossa página de exemplo:
![]() |
- em [2], a página foi obtida por meio de um GET.
- em [1], vemos os dois eventos que ocorreram durante esse GET
Se, acima, o usuário clicar no botão [Valider] [3], a página [Default.aspx] será solicitada por meio de um POST. Esse POST será acompanhado de parâmetros que corresponderão aos valores de todos os componentes incluídos na tag <form> da página [Default.aspx]: os dois TextBox e [TextBoxNom, TextBoxAge], o botão [ButtonValider] e a lista [ListBoxEvts]. Os valores enviados para os componentes são os seguintes:
- TextBox: o valor inserido
- Button: o texto do botão, neste caso, o texto “Validar”
- Listbox: o texto da mensagem selecionado no ListBox
Em resposta ao POST, obtém-se a página [4]. Trata-se novamente da página [Default.aspx]. Esse é o comportamento normal, a menos que haja transferência ou redirecionamento de página pelos gerenciadores de eventos da página. É possível observar que ocorreram dois novos eventos:
- o evento Page_Load, que ocorreu durante o carregamento da página
- o evento ButtonValider_Click, que ocorreu devido ao clique no botão [Valider]
É possível observar que:
- o evento Page_Init não ocorreu na operação HTTP POST, enquantoele ocorreu nas operações HTTP e GET
- o evento Page_Load ocorre sempre, seja em um GET ou em um POST. É nesse método que, geralmente, precisamos saber se estamos lidando com um GET ou com um POST.
- Após a execução do POST, a página [Default.aspx] foi reenviada ao cliente com as alterações feitas pelos gerenciadores de eventos. É sempre assim. Depois que os eventos de uma página P são processados, essa mesma página P é reenviada ao cliente. Há duas maneiras de contornar essa regra. O último gerenciador de eventos executado pode
- transferir o fluxo de execução para outra página P2.
- redirecionar o navegador do cliente para outra página P2.
Em ambos os casos, é a página P2 que é enviada de volta ao navegador. Os dois métodos apresentam diferenças sobre as quais voltaremos a falar.
- O evento ButtonValider_Click ocorreu após o evento Page_Load. Portanto, é esse gerenciador que pode tomar a decisão de transferir ou redirecionar para uma página P2.
- A lista de eventos [4] manteve os dois eventos exibidos durante o carregamento inicial GET da página [Default.aspx]. Isso é surpreendente, considerando que a página [Default.aspx] foi recriada durante o POST. Seria de se esperar encontrar a página [Default.aspx] com seus valores de projeto, resultando, portanto, em um ListBox vazio. A execução dos gerenciadores Page_Load e ButtonValider_Click deveria, em seguida, inserir duas mensagens. No entanto, encontramos quatro. É o mecanismo do VIEWSTATE que explica isso. Durante a execução inicial do GET, o servidor web envia a página [Default.aspx] com uma tag HTML <input type="hidden" ...>, chamada de campo oculto (linha 10 abaixo).
No campo de ID “__VIEWSTATE”, o servidor web codifica o valor de todos os componentes da página. Ele faz isso tanto no GET inicial quanto nos POST que se seguem. Quando ocorre um POST em uma página P:
- o navegador solicita a página P, enviando em sua solicitação os valores de todos os componentes que estão dentro da tag <form>. Acima, pode-se observar que o componente “__VIEWSTATE” está dentro da tag <form>. Seu valor é, portanto, enviado ao servidor durante um POST.
- A página P é instanciada e inicializada com seus valores de construção
- o componente “__VIEWSTATE” é usado para restaurar nos componentes os valores que eles tinham quando a página P foi enviada anteriormente. É assim, por exemplo, que a lista de eventos [4] recupera as duas primeiras mensagens que possuía quando foi enviada em resposta ao GET inicial do navegador.
- Os componentes da página P assumem, então, como valores aqueles enviados pelo navegador. Nesse momento, o formulário da página P está no estado em que o usuário o enviou.
- O evento Page_Load é processado. Aqui, ele adiciona uma mensagem à lista de eventos [4].
- O evento que provocou o POST é processado. Aqui, o ButtonValider_Click adiciona uma mensagem à lista de eventos [4].
- A página P é retornada. Os componentes têm como valor:
- ou o valor enviado, c.a.d; ou o valor que o componente tinha no formulário quando este foi enviado ao servidor
- ou um valor fornecido por um dos gerenciadores de eventos.
No nosso exemplo,
- os dois componentes TextBox recuperarão seus valores enviados, pois os gerenciadores de eventos não os alteram
- a lista de eventos [4] recupera seu valor enviado, c.a.d. todos os eventos já registrados na lista, mais dois novos eventos criados pelos métodos Page_Load e ButtonValider_Click.
O mecanismo do VIEWSTATE pode ser ativado ou desativado em cada componente. Vamos desativá-lo para o componente [ListBoxEvts]:
![]() |
- no [1], o VIEWSTATE do componente [ListBoxEvts] está desativado. O dos TextBox e [2] está ativado por padrão.
- No [3], os dois eventos retornados após o GET inicial
![]() |
- em [4], o formulário foi preenchido e clicou-se no botão [Valider]. Será realizada uma transição POST para a página [Default.aspx].
- em [6], o resultado retornado após clicar no botão [Valider]
- o mecanismo do VIEWSTATE ativado explica que os TextBox e [7] tenham mantido seus valores registrados no [4]
- o mecanismo do VIEWSTATE desativado explica que o componente [ListBoxEvts] [8] não tenha mantido seu conteúdo [5].
2.3. Gerenciamento dos valores enviados
Vamos nos concentrar aqui nos valores enviados pelos dois TextBox quando o usuário clica no botão [Valider]. A página [Default.aspx] no modo [Design] evolui da seguinte forma:
![]() |
O código-fonte do elemento adicionado em [1] é o seguinte:
<p>
Eléments postés au serveur :
<asp:Label ID="LabelPost" runat="server"></asp:Label>
</p>
Utilizaremos o componente [LabelPost] para exibir os valores inseridos nos dois TextBox e [2]. O código do gerenciador de eventos [Default.aspx.cs] passa a ser o seguinte:
using System;
namespace Intro
{
public partial class _Default : System.Web.UI.Page
{
protected void Page_Init(object sender, EventArgs e)
{
// registra-se o evento
ListBoxEvts.Items.Insert(0, string.Format("{0}: Page_Init", DateTime.Now.ToString("hh:mm:ss")));
}
protected void Page_Load(object sender, EventArgs e)
{
// registrando o evento
ListBoxEvts.Items.Insert(0, string.Format("{0}: Page_Load", DateTime.Now.ToString("hh:mm:ss")));
}
protected void ButtonValider_Click(object sender, EventArgs e)
{
// registra-se o evento
ListBoxEvts.Items.Insert(0, string.Format("{0}: ButtonValider_Click", DateTime.Now.ToString("hh:mm:ss")));
// exibe o nome e a idade
LabelPost.Text = string.Format("nom={0}, age={1}", TextBoxNom.Text.Trim(), TextBoxAge.Text.Trim());
}
}
}
Na linha 24, atualiza-se o componente LabelPost:
- LabelPost é do tipo [System.Web.UI.WebControls.Label] (ver Default.aspx.designer.cs). Sua propriedade Text representa o texto exibido pelo componente.
- TextBoxNom e TextBoxAge são do tipo [System.Web.UI.WebControls.TextBox]. A propriedade Text de um componente TextBox é o texto exibido na área de entrada.
- O método Trim() remove os espaços que possam preceder ou seguir uma sequência de caracteres
Conforme explicado anteriormente, quando o método ButtonValider_Click é executado, os componentes da página assumem o valor que tinham quando a página foi enviada pelo usuário. As propriedades Text dos dois TextBox têm, portanto, como valor os textos digitados pelo usuário no navegador.
Veja um exemplo:
![]() |
- em [1], os valores enviados
- em [2], a resposta do servidor.
- em [3], os TextBox recuperaram seus valores enviados pelo mecanismo do VIEWSTATE ativado
- em [4], as mensagens do componente ListBoxEvts são originárias dos métodos Page_Init, Page_Load, ButtonValider_Click e de um VIEWSTATE inibido
- No [5], o componente LabelPost obteve seu valor por meio do método ButtonValider_Click. Conseguimos recuperar os dois valores inseridos pelo usuário nos componentes TextBox e [1].
Vemos acima que o valor enviado para a idade é a string “yy”, um valor inválido. Vamos adicionar à página componentes chamados validadores. Eles servem para verificar a validade dos dados enviados. Essa validade pode ser verificada em dois locais:
- no cliente. Uma opção de configuração do validador permite definir se os testes devem ou não ser realizados no navegador. Nesse caso, eles são executados por código JavaScript incorporado na página HTML. Quando o usuário envia os valores inseridos no formulário, estes são verificados inicialmente pelo código JavaScript. Se algum dos testes falhar, o envio não é realizado. Assim, evita-se uma ida e volta com o servidor, tornando a página mais responsiva.
- no servidor. Embora as verificações no lado do cliente possam ser opcionais, no lado do servidor elas são obrigatórias, independentemente de ter havido verificação no lado do cliente ou não. De fato, quando uma página recebe valores enviados, ela não tem como saber se eles foram verificados pelo cliente antes do envio. No lado do servidor, o desenvolvedor deve, portanto, sempre verificar a validade dos dados enviados.
A página [Default.aspx] é alterada da seguinte forma:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="Intro._Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Introduction ASP.NET</title>
</head>
<body>
<h3>Introduction à ASP.NET</h3>
<form id="form1" runat="server">
<div>
<table>
<tr>
<td>
Nom</td>
<td>
<asp:TextBox ID="TextBoxNom" runat="server"></asp:TextBox>
</td>
<td>
<asp:RequiredFieldValidator ID="RequiredFieldValidatorNom" runat="server"
ControlToValidate="TextBoxNom" Display="Dynamic"
ErrorMessage="Donnée obligatoire !"></asp:RequiredFieldValidator>
</td>
</tr>
<tr>
<td>
Age</td>
<td>
<asp:TextBox ID="TextBoxAge" runat="server"></asp:TextBox>
</td>
<td>
<asp:RequiredFieldValidator ID="RequiredFieldValidatorAge" runat="server"
ControlToValidate="TextBoxAge" Display="Dynamic"
ErrorMessage="Donnée obligatoire !"></asp:RequiredFieldValidator>
<asp:RangeValidator ID="RangeValidatorAge" runat="server"
ControlToValidate="TextBoxAge" Display="Dynamic"
ErrorMessage="Tapez un nombre entre 1 et 150 !" MaximumValue="150"
MinimumValue="1" Type="Integer"></asp:RangeValidator>
</td>
</tr>
</table>
</div>
<asp:Button ID="ButtonValider" runat="server" onclick="ButtonValider_Click"
Text="Valider" CausesValidation="False"/>
<hr />
<p>
Evénements traités par le serveur</p>
<p>
<asp:ListBox ID="ListBoxEvts" runat="server" EnableViewState="False">
</asp:ListBox>
</p>
<p>
Eléments postés au serveur :
<asp:Label ID="LabelPost" runat="server"></asp:Label>
</p>
<p>
Eléments validés par le serveur :
<asp:Label ID="LabelValidation" runat="server"></asp:Label>
</p>
<asp:Label ID="LabelErreursSaisie" runat="server" ForeColor="Red"></asp:Label>
</form>
</body>
</html>
Os validadores foram adicionados às linhas 20, 32 e 35. Na linha 58, um componente Label é utilizado para exibir os valores enviados válidos. Na linha 60, um componente Label é utilizado para exibir uma mensagem de erro caso haja erros de entrada.
A página [Default.aspx] no modo [Design] é a seguinte:
![]() |
- os componentes [1] e [2] são do tipo RequiredFieldValidator. Esse validador verifica se um campo de entrada não está vazio.
- O componente [3] é do tipo RangeValidator. Este validador verifica se um campo de entrada contém um valor entre dois limites.
- No [4], as propriedades do validador [1].
Apresentaremos os dois tipos de validadores por meio de suas tags no código da página [Default.aspx]:
<asp:RequiredFieldValidator ID="RequiredFieldValidatorNom" runat="server"
ControlToValidate="TextBoxNom" Display="Dynamic"
ErrorMessage="Donnée obligatoire !"></asp:RequiredFieldValidator>
- ID: o identificador do componente
- ControlToValidate: o nome do componente cujo valor é verificado. Aqui, queremos que o componente TextBoxNom não tenha um valor vazio (cadeia vazia ou sequência de espaços)
- ErrorMessage: mensagem de erro a ser exibida no validador em caso de dados inválidos.
- EnableClientScript: valor booleano que indica se o validador também deve ser executado no lado do cliente. Esse atributo tem o valor True por padrão quando não é explicitamente definido como acima.
- Display: modo de exibição do validador. Existem dois modos:
- static (padrão): o validador ocupa espaço na página, mesmo que não exiba nenhuma mensagem de erro
- dynamic: o validador não ocupa espaço na página se não exibir nenhuma mensagem de erro.
<asp:RangeValidator ID="RangeValidatorAge" runat="server"
ControlToValidate="TextBoxAge" Display="Dynamic"
ErrorMessage="Tapez un nombre entre 1 et 150 !" MaximumValue="150"
MinimumValue="1" Type="Integer"></asp:RangeValidator>
- Tipo: o tipo do dado verificado. Aqui, a idade é um número inteiro.
- MinimumValue, MaximumValue: os limites dentro dos quais o valor verificado deve estar
A configuração do componente que gera o POST influencia o modo de validação. Aqui, esse componente é o botão [Valider]:
<asp:Button ID="ButtonValider" runat="server" onclick="ButtonValider_Click" Text="Valider" CausesValidation="True" />
- CausesValidation: define o modo automático ou o nome das validações no lado do servidor. Esse atributo tem o valor padrão “True” se não for explicitamente mencionado. Nesse caso,
- no lado do cliente, os validadores com nomes de EnableClientScript a True são executados. O POST só ocorre se todos os validadores do lado do cliente forem bem-sucedidos.
- No lado do servidor, todos os validadores presentes na página são executados automaticamente antes do processamento do evento que provocou o POST. Nesse caso, eles seriam executados antes da execução do método ButtonValider_Click. Nesse método, é possível saber se todas as validações foram bem-sucedidas ou não. Page.IsValid é “True” se todas tiverem sido bem-sucedidas, “False” caso contrário. Neste último caso, é possível interromper o processamento do evento que provocou o POST. A página enviada é devolvida exatamente como foi inserida. Os validadores que falharam exibem, então, suas mensagens de erro (atributo ErrorMessage).
Se CausesValidation tiver o valor False, então
- no lado do cliente, nenhum validador é executado
- No lado do servidor, cabe ao desenvolvedor solicitar ele mesmo a execução dos validadores da página. Ele faz isso com o método Page.Validate(). Dependendo do resultado das validações, esse método define a propriedade Page.IsValid como “True” ou “False”.
No [Default.aspx.cs], o código de processamento do ButtonValider_Click sofre as seguintes alterações:
protected void ButtonValider_Click(object sender, EventArgs e)
{
// registra-se o evento
ListBoxEvts.Items.Insert(0, string.Format("{0}: ButtonValider_Click", DateTime.Now.ToString("hh:mm:ss")));
// exibe-se o nome e a idade
LabelPost.Text = string.Format("nom={0}, age={1}", TextBoxNom.Text.Trim(), TextBoxAge.Text.Trim());
// a página está válida?
Page.Validate();
if (!Page.IsValid)
{
// mensagem de erro geral
LabelErreursSaisie.Text = "Veuillez corriger les erreurs de saisie...";
LabelErreursSaisie.Visible = true;
return;
}
// oculta-se a mensagem de erro
LabelErreursSaisie.Visible = false;
// exibe-se o nome e a idade validados
LabelValidation.Text = string.Format("nom={0}, age={1}", TextBoxNom.Text.Trim(), TextBoxAge.Text.Trim());
}
Caso o botão [Valider] tenha seu atributo CausesValidation definido como True e os validadores tenham seus atributos EnableClientScript definidos como True, o método ButtonValider_Click só é executado quando os valores enviados são válidos. Pode-se então questionar o significado do código que aparece a partir da linha 8. É preciso lembrar que sempre é possível escrever um cliente programado que envie valores não verificados para a página [Default.aspx]. Portanto, essa página deve sempre refazer os testes de validade.
- linha 8: inicia a execução de todos os validadores da página. Caso o botão [Valider] tenha seu atributo definido de CausesValidation a True, isso é feito automaticamente e não há necessidade de repeti-lo. Há redundância aqui.
- linhas 9-15: caso em que um dos validadores tenha falhado
- linhas 16-19: caso em que todos os validadores foram bem-sucedidos
Aqui estão dois exemplos de execução:
![]() |
- em [1], um exemplo de execução no caso em que:
- o botão [Valider] tenha sua propriedade alterada de CausesValidation para True
- os validadores tenham sua propriedade EnableClientScript alterada para True
As mensagens de erro [2] foram exibidas pelos validadores executados no lado do cliente pelo código JavaScript da página. Não houve envio de POST para o servidor, conforme mostra o rótulo dos elementos enviados [3].
- Em [4], um exemplo de execução no caso em que:
- o botão [Valider] tenha sua propriedade CausesValidation definida como False
- os validadores tenham sua propriedade EnableClientScript alterada de False
As mensagens de erro [5] foram exibidas pelos validadores executados no lado do servidor. Conforme mostra [6], houve de fato um POST enviado ao servidor. Em [7], a mensagem de erro exibida pelo método [ButtonValider_Click] em caso de erros de entrada.
![]() |
- no [8], um exemplo obtido com dados válidos. O [9,10] mostra que os elementos postados foram validados. Ao realizar testes repetidos, é necessário definir a propriedade EnableViewState do rótulo [LabelValidation] como False para que a mensagem de validação não permaneça exibida ao longo das execuções.
2.4. Gerenciamento de dados de escopo do aplicativo
Voltemos à arquitetura de execução de uma página ASPX:
![]() |
A classe da página ASPX é instanciada no início da solicitação do cliente e destruída ao final dela. Portanto, ela não pode ser usada para armazenar dados entre duas solicitações. Pode-se querer armazenar dois tipos de dados:
- dados compartilhados por todos os usuários do aplicativo web. Geralmente, trata-se de dados somente para leitura. Três arquivos são utilizados para implementar esse compartilhamento de dados:
- [Web.Config]: o arquivo de configuração da aplicação
- [Global.asax, Global.asax.cs]: permite definir uma classe, chamada classe global da aplicação, cuja duração corresponde à da própria aplicação, bem como manipuladores para determinados eventos dessa mesma aplicação.
A classe global da aplicação permite definir dados que estarão disponíveis para todas as solicitações de todos os usuários.
- dados compartilhados pelas solicitações de um mesmo cliente. Esses dados são armazenados em um objeto chamado Sessão. Fala-se, então, em sessão do cliente para designar a memória do cliente. Todas as solicitações de um cliente têm acesso a essa sessão. Elas podem armazenar e ler informações nela
![]() |
Acima, mostramos os tipos de memória aos quais uma página tem acesso:
- a memória do aplicativo, que na maioria das vezes contém dados somente para leitura e é acessível a todos os usuários;
- a memória de um usuário específico, ou sessão, que contém dados de leitura/gravação e é acessível às solicitações sucessivas do mesmo usuário.
- Embora não esteja representada acima, existe uma memória de solicitação, ou contexto de solicitação. A solicitação de um usuário pode ser processada por várias páginas ASPX sucessivas. O contexto da solicitação permite que uma página 1 transmita informações para uma página 2.
Estamos interessados aqui nos dados de escopo Application, aqueles que são compartilhados por todos os usuários. A classe global do aplicativo pode ser criada da seguinte forma:
![]() |
- em [1], adiciona-se um novo elemento ao projeto
- em [2], adiciona-se a classe global do aplicativo
- em [3], mantém-se o nome padrão [Global.asax] para o novo elemento
![]() |
- em [4], dois novos arquivos foram adicionados ao projeto
- em [5], exibe-se a marcação de [Global.asax]
<%@ Application Codebehind="Global.asax.cs" Inherits="Intro.Global" Language="C#" %>
- A tag Application substitui a tag Page que tínhamos para [Default.aspx]. Ela identifica a classe de aplicação global
- Codebehind: define o arquivo no qual a classe de aplicativo global está definida
- Inherits: define o nome dessa classe
A classe Intro.Global gerada é a seguinte:
using System;
namespace Intro
{
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
}
protected void Session_Start(object sender, EventArgs e)
{
}
protected void Application_BeginRequest(object sender, EventArgs e)
{
}
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
}
protected void Application_Error(object sender, EventArgs e)
{
}
protected void Session_End(object sender, EventArgs e)
{
}
protected void Application_End(object sender, EventArgs e)
{
}
}
}
- linha 5: a classe global de aplicação deriva da classe HttpApplication
A classe é gerada com esqueletos de manipuladores de eventos da aplicação:
- linhas 8, 38: gerenciam os eventos Application_Start (inicialização da aplicação) e Application_End (encerramento da aplicação quando o servidor web é desligado ou quando o administrador encerra a aplicação)
- linhas 13, 33: gerenciam os eventos Session_Start (início de uma nova sessão de cliente ao chegada de um novo cliente ou ao término de uma sessão existente) e Session_End (fim de uma sessão de cliente, seja explicitamente por programação, seja implicitamente por exceder o tempo permitido para uma sessão).
- linha 28: gerencia o evento Application_Error (ocorrência de uma exceção não tratada pelo código do aplicativo e encaminhada ao servidor)
- linha 18: gerencia o evento Application_BeginRequest (chegada de uma nova solicitação).
- linha 23: gerencia o evento Application_AuhenticateRequest (ocorre quando um usuário se autentica).
O método [Application_Start] é frequentemente utilizado para inicializar a aplicação a partir das informações contidas em [Web.Config]. Aquele gerado na criação inicial de um projeto tem a seguinte aparência:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
...
</configSections>
<appSettings/>
<connectionStrings/>
<system.web>
...
</system.web>
<system.codedom>
....
</system.codedom>
<!--
La section system.webServer est requise pour exécuter ASP.NET AJAX sur Internet
Information Services 7.0. Elle n'est pas nécessaire pour les versions précédentes d'IIS.
-->
<system.webServer>
...
</system.webServer>
<runtime>
....
</runtime>
</configuration>
Para nossa aplicação atual, esse arquivo é desnecessário. Se ele for excluído ou renomeado, a aplicação continuará funcionando normalmente. Vamos nos concentrar nas tags das linhas 8 e 9:
- <appsettings> permite definir um dicionário de informações
- <connectionStrings> permite definir cadeias de conexão a bancos de dados
Consideremos o seguinte arquivo [Web.config]:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
...
</configSections>
<appSettings>
<add key="cle1" value="valeur1"/>
<add key="cle2" value="valeur2"/>
</appSettings>
<connectionStrings>
<add connectionString="connectionString1" name="conn1"/>
</connectionStrings>
<system.web>
...
Esse arquivo pode ser utilizado pela seguinte classe global de aplicação:
using System;
using System.Configuration;
namespace Intro
{
public class Global : System.Web.HttpApplication
{
public static string Param1 { get; set; }
public static string Param2 { get; set; }
public static string ConnString1 { get; set; }
public static string Erreur { get; set; }
protected void Application_Start(object sender, EventArgs e)
{
try
{
Param1 = ConfigurationManager.AppSettings["cle1"];
Param2 = ConfigurationManager.AppSettings["cle2"];
ConnString1 = ConfigurationManager.ConnectionStrings["conn1"].ConnectionString;
}
catch (Exception ex)
{
Erreur = string.Format("Erreur de configuration : {0}", ex.Message);
}
}
protected void Session_Start(object sender, EventArgs e)
{
}
}
}
- linhas 8-11: quatro propriedades estáticas P. Como o tempo de vida da classe Global é o mesmo da aplicação, qualquer consulta feita à aplicação terá acesso a essas propriedades P por meio da sintaxe Global.P.
- linhas 17-19: o arquivo [Web.config] é acessível por meio da classe [System.Configuration.ConfigurationManager]
- linhas 17-18: recupera os elementos da tag <appSettings> do arquivo [Web.config] por meio do atributo key.
- linha 19: recupera os elementos da tag <connectionStrings> do arquivo [Web.config] por meio do atributo name.
Os atributos estáticos das linhas 8 a 11 podem ser acessados por qualquer manipulador de eventos das páginas ASPX carregadas. Nós os utilizamos no manipulador [Page_Load] da página [Default.aspx]:
protected void Page_Load(object sender, EventArgs e)
{
// o evento é registrado
ListBoxEvts.Items.Insert(0, string.Format("{0}: Page_Load", DateTime.Now.ToString("hh:mm:ss")));
// recuperam-se as informações da classe global da aplicação
LabelGlobal.Text = string.Format("Param1={0},Param2={1},ConnString1={2},Erreur={3}", Global.Param1, Global.Param2, Global.ConnString1, Global.Erreur);
}
- linha 6: os quatro atributos estáticos da classe global da aplicação são utilizados para preencher um novo rótulo da página [Default.aspx]
![]() |
Ao executar, obtemos o seguinte resultado:
![]() |
Acima, vemos que os parâmetros de [web.config] foram recuperados corretamente. A classe global da aplicação é o local adequado para armazenar informações compartilhadas por todos os usuários.
2.5. Gerenciamento de dados no escopo da sessão
Aqui, vamos nos concentrar em como armazenar informações ao longo das solicitações de um determinado usuário:
![]() |
Cada usuário possui sua própria memória, chamada de sessão.
Vimos que a classe de aplicação global dispõe de dois gerenciadores para lidar com os eventos:
- Session_Start: início de uma sessão
- Session_end: fim de uma sessão
O mecanismo de sessão é implementado da seguinte maneira:
- na primeira solicitação de um usuário, o servidor web cria um token de sessão e o atribui ao usuário. Esse token é uma sequência de caracteres única para cada usuário. Ele é enviado pelo servidor na resposta à primeira solicitação do usuário.
- nas solicitações seguintes, o usuário (o navegador da web) inclui em sua solicitação o token de sessão que lhe foi atribuído. Assim, o servidor web é capaz de reconhecê-lo.
- Uma sessão tem um tempo de vida. Quando o servidor web recebe uma solicitação de um usuário, ele calcula o tempo decorrido desde a solicitação anterior. Se esse tempo ultrapassar o tempo de vida da sessão, uma nova sessão é criada para o usuário. Os dados da sessão anterior são perdidos. No servidor web IIS (Internet Information Server) da Microsoft, as sessões têm, por padrão, uma duração de 20 minutos. Esse valor pode ser alterado pelo administrador do servidor web.
- O servidor web sabe que está lidando com a primeira solicitação de um usuário porque essa solicitação não contém um token de sessão. É a única.
Qualquer página ASP.NET tem acesso à sessão do usuário por meio da propriedade Session da página, do tipo [System.Web.SessionState.HttpSessionState]. Utilizaremos as seguintes propriedades P e métodos M da classe HttpSessionState:
Nome | Tipo | Função |
Item[String clé] | P | A sessão pode ser estruturada como um dicionário. Item[clé] é o elemento da sessão identificado por clé. Em vez de escrever [HttpSessionState].Item[clé], também é possível escrever [HttpSessionState].[clé]. |
Limpar | M | esvazia o dicionário da sessão |
Cancelar | M | encerra a sessão. A sessão deixa de ser válida. Uma nova sessão será iniciada com a próxima solicitação do usuário. |
Como exemplo de memória do usuário, vamos contar o número de vezes que um usuário clica no botão [Valider]. Para obter esse resultado, é necessário manter um contador na sessão do usuário.
A página [Default.aspx] é atualizada da seguinte forma:
![]() |
A classe global de aplicação [Global.asax.cs] evolui da seguinte forma:
using System;
using System.Configuration;
namespace Intro
{
public class Global : System.Web.HttpApplication
{
public static string Param1 { get; set; }
...
protected void Application_Start(object sender, EventArgs e)
{
...
}
protected void Session_Start(object sender, EventArgs e)
{
// contador de solicitações
Session["nbRequêtes"] = 0;
}
}
}
Na linha 19, utiliza-se a sessão do usuário para armazenar um contador de solicitações identificado pela chave “nbRequêtes”. Esse contador é atualizado pelo gerenciador [ButtonValider_Click] da página [Default.aspx]:
using System;
namespace Intro
{
public partial class _Default : System.Web.UI.Page
{
....
protected void ButtonValider_Click(object sender, EventArgs e)
{
// registra-se o evento
ListBoxEvts.Items.Insert(0, string.Format("{0}: ButtonValider_Click", DateTime.Now.ToString("hh:mm:ss")));
// exibe o nome e a idade postados
LabelPost.Text = string.Format("nom={0}, age={1}", TextBoxNom.Text.Trim(), TextBoxAge.Text.Trim());
// número de solicitações
Session["nbRequêtes"] = (int)Session["nbRequêtes"] + 1;
LabelNbRequetes.Text = Session["nbRequêtes"].ToString();
// a página é válida?
Page.Validate();
if (!Page.IsValid)
{
...
}
...
}
}
}
- linha 16: o contador de solicitações é incrementado
- linha 17: o contador é exibido na página
Veja um exemplo de execução:
![]() |
2.6. Gerenciamento do GET / POST no carregamento de uma página
Mencionamos que existem dois tipos de solicitações para uma página ASPX:
- a solicitação inicial do navegador feita com um comando HTTP GET. O servidor responde enviando a página solicitada. Vamos supor que essa página seja um formulário, c.a.d, e que, na página ASPX enviada, haja uma tag <form runat="server"...>.
- As solicitações seguintes são feitas pelo navegador em resposta a determinadas ações do usuário no formulário. O navegador então faz uma solicitação HTTP POST.
Seja em uma solicitação GET ou em uma solicitação POST, o método [Page_Load] é executado. No GET, esse método é normalmente utilizado para inicializar a página enviada ao navegador do cliente. Em seguida, por meio do mecanismo do VIEWSTATE, a página permanece inicializada e só é modificada pelos gerenciadores de eventos que acionam os POST. Não há necessidade de reinicializar a página no Page_Load. Daí a necessidade desse método saber se a solicitação do cliente é um GET ou um POST.
Vejamos o exemplo a seguir. Adicionamos uma lista suspensa à página [Default.aspx]. O conteúdo dessa lista será definido no gerenciador Page_Load da solicitação GET:
![]() |
A lista suspensa é declarada em [Default.aspx.designer.cs] da seguinte maneira:
protected global::System.Web.UI.WebControls.DropDownList DropDownListNoms;
Utilizaremos os seguintes métodos M e propriedades P da classe [DropDownList]:
Nome | Tipo | Função |
Itens | P | a coleção do tipo ListItemCollection dos itens do tipo ListItem da lista suspensa |
SelectedIndex | P | o índice, começando em 0, do elemento selecionado na lista suspensa quando o formulário é enviado |
SelectedItem | P | o elemento do tipo ListItem selecionado na lista suspensa quando o formulário é enviado |
SelectedValue | P | o valor do tipo string do elemento do tipo ListItem selecionado na lista suspensa quando o formulário é enviado. Definiremos em breve esse conceito de valor. |
A classe ListItem dos elementos de uma lista suspensa serve para gerar as tags <option> da tag HTML <select>:
Na tag <option>
- textei é o texto exibido na lista suspensa
- vali é o valor enviado pelo navegador se textei for o texto selecionado na lista suspensa
Cada opção pode ser gerada por um objeto LisItem criado por meio do construtor ListItem(string texto, string valor).
Em [Default.aspx.cs], o código do manipulador [Page_Load] evolui da seguinte forma:
protected void Page_Load(object sender, EventArgs e)
{
// registra-se o evento
...
// recuperam-se as informações da classe global do aplicativo
...
// inicialização da lista suspensa de nomes apenas durante o GET inicial
if (!IsPostBack)
{
for (int i = 0; i < 3; i++)
{
DropDownListNoms.Items.Add(new ListItem("nom"+i,i.ToString()));
}
}
}
- linha 8: a classe Page possui um atributo IsPostBack do tipo booleano. Na verdade, isso significa que a solicitação do usuário é um POST. As linhas 10 a 13, portanto, são executadas apenas no GET inicial do cliente.
- linha 12: adiciona-se à lista [DropDownListNoms] um elemento do tipo ListItem (string texto, string valor). O texto exibido para o (i+1)º elemento será nomi e o valor enviado para esse elemento, caso seja selecionado, será i.
O gerenciador [ButtonValider_Click] é modificado para exibir o valor enviado pela lista suspensa:
protected void ButtonValider_Click(object sender, EventArgs e)
{
// registra-se o evento
...
// exibe-se os valores postados
LabelPost.Text = string.Format("nom={0}, age={1}, combo={2}", TextBoxNom.Text.Trim(), TextBoxAge.Text.Trim(), DropDownListNoms.SelectedValue);
// número de consultas
...
}
Na linha 6, o valor lançado para a lista [DropDownListNoms] é obtido por meio da propriedade SelectedValue da lista. Veja um exemplo de execução:
![]() |
- em [1], o conteúdo da lista suspensa após o GET inicial e logo antes do primeiro POST
- em [2], a página após o primeiro POST.
- em [3], o valor enviado para a lista suspensa. Corresponde ao atributo value do ListItem selecionado na lista.
- em [4], a lista suspensa. Ela contém os mesmos elementos que após o GET inicial. É o mecanismo do VIEWSTATE que explica isso.
Para compreender a interação entre o VIEWSTATE da lista DropDownListNoms e o teste if (! IsPostBack) do gerenciador Page_Load do [Default.aspx], o leitor é convidado a refazer o teste anterior com as seguintes configurações:
Caso | DropDownListNoms.EnableViewState | teste if(! IsPostBack) em Page_Load de [Default.aspx] |
Os diferentes testes apresentam os seguintes resultados:
- este é o caso apresentado acima
- a lista é preenchida durante o GET inicial, mas não durante os POST subsequentes. Como o EnableViewState está incorreto, a lista fica vazia após cada POST
- a lista é preenchida tanto após o GET inicial quanto nos POST subsequentes. Como o EnableViewState corresponde ao vrai, temos 3 nomes após o GET inicial, 6 nomes após o primeiro POST, 9 nomes após o segundo POST, ...
- A lista é preenchida tanto após o GET inicial quanto durante os POST subsequentes. Como o EnableViewState é igual ao faux, a lista é preenchida com apenas 3 nomes a cada solicitação, seja ela a solicitação inicial GET ou as solicitações POST que se seguem. Observamos o mesmo comportamento do caso 1. Portanto, há duas maneiras de obter o mesmo resultado.
2.7. Gerenciamento do VIEWSTATE dos elementos de uma página ASPX
Por padrão, todos os elementos de uma página ASPX têm sua propriedade EnableViewState definida como True. Sempre que a página ASPX é enviada ao navegador do cliente, ela contém o campo oculto __VIEWSTATE, cujo valor é uma sequência de caracteres que codifica o conjunto de valores dos componentes cujas propriedades variam de EnableViewState a True. Para minimizar o tamanho dessa sequência, pode-se tentar reduzir o número de componentes cujas propriedades variam de EnableViewState a True.
Vale lembrar como os componentes de uma página ASPX obtêm seus valores após a execução de um POST:
- a página ASPX é instanciada. Os componentes são inicializados com seus valores de projeto.
- o valor __VIEWSTATE enviado pelo navegador é usado para atribuir aos componentes o valor que eles tinham quando a página ASPX foi enviada ao navegador na vez anterior.
- os valores enviados pelo navegador são atribuídos aos componentes
- os manipuladores de eventos são executados. Eles podem alterar o valor de certos componentes.
A partir dessa sequência, deduz-se que os componentes que:
- têm seus valores enviados
- têm seu valor alterado por um manipulador de eventos
podem ter sua propriedade alterada de EnableViewState para Faux, uma vez que seu valor de VIEWSTATE (etapa 2) será alterado por uma das etapas 3 ou 4.
A lista de componentes da nossa página está disponível em [Default.aspx.designer.cs]:
namespace Intro {
public partial class _Default {
protected global::System.Web.UI.HtmlControls.HtmlForm form1;
protected global::System.Web.UI.WebControls.TextBox TextBoxNom;
protected global::System.Web.UI.WebControls.RequiredFieldValidator RequiredFieldValidatorNom;
protected global::System.Web.UI.WebControls.TextBox TextBoxAge;
protected global::System.Web.UI.WebControls.RequiredFieldValidator RequiredFieldValidatorAge;
protected global::System.Web.UI.WebControls.RangeValidator RangeValidatorAge;
protected global::System.Web.UI.WebControls.DropDownList DropDownListNoms;
protected global::System.Web.UI.WebControls.Button ButtonValider;
protected global::System.Web.UI.WebControls.ListBox ListBoxEvts;
protected global::System.Web.UI.WebControls.Label LabelPost;
protected global::System.Web.UI.WebControls.Label LabelValidation;
protected global::System.Web.UI.WebControls.Label LabelErreursSaisie;
protected global::System.Web.UI.WebControls.Label LabelGlobal;
protected global::System.Web.UI.WebControls.Label LabelNbRequetes;
}
}
O valor da propriedade EnableViewState desses componentes poderia ser o seguinte:
Composant | Valor lançado | EnableViewState | Pourquoi |
TextBoxNom | valor inserido no TextBox | False | o valor do componente é lançado |
TextBoxAge | idem | ||
RequiredFieldValidatorNom | nenhum | False | ausência de valor para o componente |
RequiredFieldValidatorAge | idem | ||
RangeValidatorAge | idem | ||
LabelPost | nenhuma | False | obtém seu valor por meio de um gerenciador de eventos |
LabelValidation | idem | ||
LabelErreursSaisie | idem | ||
LabelGlobal | idem | ||
LabelNbRequetes | idem | ||
DropDownListNoms | "valor" do elemento selecionado | True | queremos manter o conteúdo da lista ao longo das consultas sem precisar regenerá-la |
ListBoxEvts | "value" do elemento selecionado | False | o conteúdo da lista é gerado por um gerenciador de eventos |
ButtonValider | texto do botão | False | o componente mantém seu valor de projeto |
2.8. Redirecionamento de uma página para outra
Até agora, as operações GET e POST sempre retornavam a mesma página [Default.aspx]. Vamos considerar o caso em que uma solicitação é processada por duas páginas ASPX sucessivas, [Default.aspx] e [Page1.aspx], e em que é esta última que é retornada ao cliente. Além disso, veremos como a página [Default.aspx] pode transmitir informações para a página [Page1.aspx] por meio de uma memória que chamaremos de memória da solicitação.
![]() |
Estamos construindo a página [Page1.aspx]:
![]() |
- em [1], adicionamos um novo elemento ao projeto
- em [2], adicionamos um elemento [Web Form] denominado [Page1.aspx] [3]
![]() |
- no [4], a página adicionada
- em [5], a página já gerada
O código-fonte de [Page1.aspx] é o seguinte:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Page1.aspx.cs" Inherits="Intro.Page1" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>Page1</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<h1>
Page 1</h1>
<asp:Label ID="Label1" runat="server"></asp:Label>
<br />
<asp:HyperLink ID="HyperLink1" runat="server" NavigateUrl="~/Default.aspx">Retour
vers page [Default]</asp:HyperLink>
</div>
</form>
</body>
</html>
- linha 13: um rótulo que servirá para exibir uma informação transmitida pela página [Default.aspx]
- linha 15: um link HTML para a página [Default.aspx]. Quando o usuário clica nesse link, o navegador solicita a página [Default.aspx] por meio de uma operação GET. A página [Default.aspx] é então carregada como se o usuário tivesse digitado diretamente sua URL no navegador.
A página [Default.aspx] é complementada com um novo componente do tipo LinkButton:
![]() |
O código-fonte desse novo componente é o seguinte:
<asp:LinkButton ID="LinkButtonToPage1" runat="server" CausesValidation="False"
EnableViewState="False" onclick="LinkButtonToPage1_Click">Forward vers Page1</asp:LinkButton>
- CausesValidation="False": clicar no link provocará um POST para [Defaul.aspx]. O componente [LinkButton] se comporta da mesma forma que o componente [Button]. Neste caso, não se deseja que o clique no link acione a execução dos validadores.
- EnableViewState="False": não há necessidade de manter o estado do link ao longo das solicitações. Ele mantém seus valores de projeto.
- onclick="LinkButtonToPage1_Click": nome do método que, em [Defaul.aspx.cs], gerencia o evento Click no componente LinkButtonToPage1.
O código do manipulador LinkButtonToPage1_Click é o seguinte:
// para a Página 1
protected void LinkButtonToPage1_Click(object sender, EventArgs e)
{
// insere-se informações no contexto
Context.Items["msg1"] = "Message de Default.aspx pour Page1";
// encaminhamos a solicitação para a Página 1
Server.Transfer("Page1.aspx",true);
}
Na linha 7, a solicitação é encaminhada para a página [Page1.aspx] por meio do método [Server.Transfer]. O segundo parâmetro do método, que é true, indica que todas as informações enviadas para [Default.aspx] durante a execução de POST devem ser repassadas para [Page1.aspx]. Isso permite, por exemplo, que o [Page1.aspx] tenha acesso aos valores postados por meio de uma coleção chamada Request.Form. A linha 5 utiliza o que é chamado de contexto da solicitação. O acesso a ele é feito por meio da propriedade Context da classe Page. Esse contexto pode servir como memória entre as diferentes páginas que processam a mesma solicitação, neste caso, [Default.aspx] e [Page1.aspx]. Para isso, utiliza-se o dicionário Items.
Quando [Page1.aspx] é carregada pela operação Server.Transfer("Page1.aspx",true), tudo ocorre como se [Page1.aspx] tivesse sido chamada por um GET de um navegador. O gerenciador Page_Load de [Page1.aspx] é executado normalmente. Vamos usá-lo para exibir a mensagem inserida por [Default.aspx] no contexto da solicitação:
using System;
namespace Intro
{
public partial class Page1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Label1.Text = Context.Items["msg1"] as string;
}
}
}
Na linha 9, a mensagem inserida pelo [Default.aspx] no contexto da consulta é exibida no Label1.
Veja um exemplo de execução:
![]() |
- na página [Default.aspx] [1], clica-se no link [2], que nos leva à página Page1
- em [3], a página Page1 é exibida
- em [4], a mensagem criada em [Default.aspx] e exibida por [Page1.aspx]
- em [5], a página URL exibida no navegador é a da página [Default.aspx]
2.9. Redirecionamento de uma página para outra
Apresentamos aqui outra técnica funcionalmente semelhante à anterior: quando o usuário solicita a página [Default.aspx] por meio de uma POST, ele recebe como resposta outra página, a [Page2.aspx]. No método anterior, a solicitação do usuário era processada sucessivamente por duas páginas: [Default.aspx] e [Page1.aspx]. No método de redirecionamento de página que apresentamos agora, há duas solicitações distintas do navegador:
![]() |
- em [1], o navegador faz uma solicitação POST à página [Default.aspx]. Esta processa a solicitação e envia uma resposta chamada de redirecionamento ao navegador. Essa resposta é um simples fluxo HTTP (linhas de texto) solicitando que o navegador seja redirecionado para outra URL, [Page2.aspx]. [Default.aspx] não envia o fluxo HTML nessa primeira resposta.
- Em [2], o navegador faz uma solicitação GET à página [Page2.aspx]. Esta é então enviada como resposta ao navegador.
- Se a página [Default.aspx] desejar transmitir informações para a página [Page2.aspx], ela poderá fazê-lo por meio da sessão do usuário. Ao contrário do método anterior, o contexto da solicitação não pode ser utilizado aqui, pois há duas solicitações distintas e, portanto, dois contextos distintos. Portanto, é necessário utilizar a sessão do usuário para que as páginas se comuniquem entre si.
Assim como foi feito para [Page1.aspx], adicionamos ao projeto a página [Page2.aspx]:
![]() |
- em [1], a página [Page2.aspx] foi adicionada ao projeto
- em [2], o aspecto visual de [Page2.aspx]
- em [3], adicionamos à página [Default.aspx] um componente LinkButton [4] que redirecionará o usuário para [Page2.aspx].
O código-fonte de [Page2.aspx] é semelhante ao de [Page1.aspx]:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Page2.aspx.cs" Inherits="Intro.Page2" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>Page2</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<h1>
Page 2</h1>
<asp:Label ID="Label1" runat="server"></asp:Label>
<br />
<asp:HyperLink ID="HyperLink1" runat="server" NavigateUrl="~/Default.aspx">Retour
vers page [Default]</asp:HyperLink>
</div>
</form>
</body>
</html>
No [Default.aspx], a adição do componente LinkButton gerou o seguinte código-fonte:
<asp:LinkButton ID="LinkButtonToPage2" runat="server"
onclick="LinkButtonToPage2_Click">Redirection vers Page2</asp:LinkButton>
É o gerenciador [LinkButtonToPage2_Click] que realiza o redirecionamento para [Page2.aspx]. Seu código em [Defaul.aspx.cs] é o seguinte:
protected void LinkButtonToPage2_Click(object sender, EventArgs e)
{
// insere-se uma mensagem na sessão
Session["msg2"] = "Message de [Default.aspx] pour [Page2.aspx]";
// redireciona o cliente para [Page2.aspx]
Response.Redirect("Page2.aspx");
}
- linha 4: insere-se uma mensagem na sessão do usuário
- linha 5: o objeto Response é uma propriedade de qualquer página ASPX. Ela representa a resposta enviada ao cliente. Possui um método Redirect que faz com que a resposta enviada ao cliente seja uma ordem de redirecionamento HTTP.
Quando o navegador receber a ordem de redirecionamento para [Page2.aspx], ele executará um GET nessa página. Nessa página, o método [Page_Load] será executado. Ele será utilizado para recuperar a mensagem inserida por [Default.aspx] na sessão e exibi-la. O código [Page2.aspx.cs] é o seguinte:
using System;
namespace Intro
{
public partial class Page2 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// exibe a mensagem inserida na sessão por [Default.aspx]
Label1.Text = Session["msg2"] as string;
}
}
}
Ao executar, obtemos os seguintes resultados:
![]() |
- em [1], clica-se no link de redirecionamento de [Default.aspx]. É feita uma chamada de POST para a página [Default.aspx]
- em [2], o navegador foi redirecionado para [Page2.aspx]. Isso fica evidente pelo URL exibido pelo navegador. No método anterior, essa URL era a de [Default.aspx], pois a única solicitação feita pelo navegador foi para essa URL. Aqui, há um primeiro redirecionamento de POST para [Default.aspx] e, em seguida, sem o conhecimento do usuário, um segundo redirecionamento de GET para [Page2.aspx].
- No [3], percebe-se que o [Page2.aspx] recuperou corretamente a mensagem inserida pelo [Default.aspx] na sessão.
2.10. Conclusion
Apresentamos, por meio de alguns exemplos, os conceitos de ASP.NET que nos serão úteis no restante do documento. Essa introdução não permite compreender as sutilezas das trocas cliente/servidor de uma aplicação web. Para isso, pode-se consultar:
- Programação ASP.NET [Développement WEB avec ASP.NET 1.1 ]



































