![]() |
||||||||
|
|
||||||||


| com exemplos em VB |
| Componente para deixar forms em Vb semelhantes às telas do winnamp |
| Componente para colocar sua aplicação VB no Systray |
| Componente para transformar sua aplicação VB em serviço |
| Ferramentas úteis para quem usa Olap Server |
| |

|
||||||||||||||||||||||||||||||||
Pesquisa personalizada
Evitando a re-execução de tarefas devido ao refresh de páginas A versatilidade da web acaba causando alguns problemas para aplicações criadas para ambiente web. Um dos problemas mais conhecidos é a simplicidade com a qual o usuário, apenas pressionando F5, consegue refazer operações que não poderiam ser feitas novamente, tal como deleção e inserção de dados. Com o .NET temos novas e bem interessantes formas de resolver este problema da re-execução de páginas. Podemos criar uma classe e, utilizando herança, fazer com que seja utilizada como base para todas as páginas web. Mas como reconhecer se a requisição é uma requisição original ou um refresh de página ? Para isso podemos utilizar um algorítimo simples : Para cada requisição realizada por um usuário damos um ticket da requisição, um valor numérico incremental. Esse valor fica oculto na página, em um campo hidden e também guardado em sessão. A cada nova requisição comparamos o valor do ticket com o valor contido em sessão. Se em algum momento o valor do ticket for menor que o valor contido em sessão então é porque ocorreu um refresh da página. Podemos então sinalizar em uma propriedade da página que a chamada trata-se de um refresh, permitindo a nosso código controlar a realização de operações críticas. Vamos então criar uma classLibrary para realizar estas tarefas. Vou chamar esta classLibrary de libNotRefresh. Precisaremos adicionar nesta classLibrary uma referência para System.Web, já que isso não é default. Vamos inicialmente criar uma classe para encapsular o acesso aos valores do ticket em sessão, vou chama-la de clsTicket. Veja como fica o código, bem simples : Imports System.Web.HttpContext Public Class clsTicket
Public Shared Function NextTicket() As Integer If IsNothing(Current.Session("LastTicket")) Then Current.Session("LastTicket") = 1 Else Current.Session("LastTicket") += 1 End If Return (Current.Session("LastTicket")) End Function
Public Shared Function LastTicket() As Integer If Not IsNothing(Current.Session("LastTicket")) Then Return (Current.Session("LastTicket")) Else Current.Session("LastTicket") = 0 Return (0) End If End Function
End Class
Nesta classe podemos observar uma característica interessante que nem todos conhecem : É possível acessar os objetos do ASP.NET a partir de um componente. Toda requisição web tem um contexto, o contexto http da requisição. Então utilizando System.Web.HttpContext.Current temos acesso aos objetos do ASP.NET com os valores do contexto atual da requisição, mesmo dentro de um componente. Temos nesta classe dois métodos : LastTicket para fornecer o valor do último ticket que foi criado e NextTicket, para criar um novo ticket e fornecer seu valor. Em ambos os métodos foi tomado o cuidado de verificar se o valor em sessão está realmente preenchido. Ambos estão também definidos como shared, para simplificar o acesso a eles. O próximo passo é garantirmos que todas as páginas gerem o ticket na forma de um campo hidden. Para fazermos isso podemos criar uma classe filha de System.web.Ui.Page e fazer com que todas as páginas de nosso site herdem as características desta classe. Veja como fica : Public Class
paginaBase Inherits System.Web.UI.Page
Protected Overrides Sub OnPreRender(ByVal e As System.EventArgs) Me.RegisterHiddenField("__Ticket", clsTicket.NextTicket) MyBase.OnPreRender(e) End Sub
End Class É importante lembrarmos neste ponto de um padrão utilizado pela Microsoft nas classes do framework .NET . Para cada evento existente nestas classe existe um método equivalente com o mesmo nome do evento acrescido de "On" e definido como protected. Este método é disparado dentro das classes no momento imediatamente anterior a ocorrencia do evento e é este método que é o responsável por disparar o evento. Isso ocorre para que ao criarmos uma herança da classe possamos fazer uso do evento substituindo este método, ao invés de utilizar o evento diretamente. Isso além de simplificar o uso do evento mantém o evento disponível para as aplicações que serão simples usuárias da classe. Assim sendo, em nossa classe paginaBase fiz overrides do método onPreRender, que ocorre imediatamente antes do evento PreRender. É o momento ideal de incluir algo na resposta, no caso o campo hidden __Ticket. Para incluir este campo hidden utilizei o método RegisterHiddenField. Este método simplifica muito o trabalho pois já verifica se já existe ou não um campo hidden com este nome. Caso já exista apenas troca o valor, ao invés de duplicar o campo. Outra opção, até mais discreta, seria fazer uso do viewState. Agora que fizemos o código para gerar o campo hidden devemos preparar o código para recebe-lo de volta, testar o ticket e configurar uma nova propriedade na página, isRefresh, para determinar se está ou não ocorrendo um refresh nesta página. Para fazer isso vamos fazer um overrides no método onInit, responsável pelo evento Init do objeto Page. Veja como fica : Public Class paginaBase Inherits System.Web.UI.Page Dim _isRefresh As Boolean = False
Public ReadOnly Property isRefresh() As Boolean Get Return (_isRefresh) End Get End Property
Protected Overrides Sub OnPreRender(ByVal e As System.EventArgs) Me.RegisterHiddenField("__Ticket", clsTicket.NextTicket) MyBase.OnPreRender(e) End Sub
Protected Overrides Sub OnInit(ByVal e As System.EventArgs) Dim TickAtual, UltimoTick As Integer _isRefresh = False
UltimoTick = clsTicket.LastTicket
If IsNothing(Request.Form("__Ticket")) Then TickAtual = 0 Else TickAtual = Request.Form("__Ticket") End If
If TickAtual < UltimoTick Then _isRefresh = True End If MyBase.OnInit(e) End Sub End Class No método onInit comparamos o valor existente em sessão com o valor recebido via campo hidden. Se o valor no campo hidden for menor que o contido em sessão então ocorreu um refresh. Vamos então fazer uma página para testar isso. Vamos fazer uma página com uma caixa de texto, um botão e uma listbox. Veja como fica inicialmente o código : Public Class WebForm1 Inherits libNotRefresh.paginaBase
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
ListBox1.Items.Add(TextBox1.Text) End Sub
End Class Faça um teste inicial com relação ao refresh. Insira algumas palavras, tal como "teste1", "teste2" e "teste3" na listbox e por fim faça refresh várias vezes. Verá que por mais que tente a última palavra não será duplicada na listBox. Mas e o problema do refresh ? Por que neste exemplo ele não causa a duplicação ? Quando vemos a palavra "teste3" (por exemplo) dentro da listbox, ao darmos refresh a transmissão para o servidor será do conteúdo anterior, "teste1" e "teste2", sem o teste3. Quando o código é re-executado a palavra "teste3" é re-inserida. O mesmo acontece com labels, isso porque apesar dos labels não serem transmitidos para o servidor em um POST, eles guardam seu conteúdo no viewState. Assim sendo com relação a interface visual o problema do refresh tem impacto mínimo. Ele apenas se torna mais grave em tarefas que vão além da interface, como por exemplo a inserção de um registro. Veja o código a seguir : Public Class WebForm1 Inherits libNotRefresh.paginaBase
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
ListBox1.Items.Add(TextBox1.Text) cmd.Parameters("texto").Value = TextBox1.Text CN.Open() cmd.ExecuteNonQuery() CN.Close() End Sub
End Class Criei um command e uma conexão para gravar o conteúdo da textbox em uma tabela de um banco de dados. Se após isso você testar novamente o refresh, observará na tabela do banco que o texto será duplicado de acordo com o número de vezes que você fizer refresh. Para fazermos com que isso não aconteça agora é bem simples : Basta alterarmos a herança, para que nossa página herde da classe paginaBase e inserirmos no click do botão um if para testar a nova propriedade isRefresh. Veja como fica : Public Class WebForm1 Inherits libNotRefresh.paginaBase
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
ListBox1.Items.Add(TextBox1.Text) If Not isRefresh Then cmd.Parameters("texto").Value = TextBox1.Text CN.Open() cmd.ExecuteNonQuery() CN.Close() End If End Sub
End Class Pronto. Testando novamente você observará que a inserção no banco não mais será duplicada. Basta fazermos o mesmo em todas as nossas páginas, trocarmos a herança e testarmos a propriedade isRefresh, para desta forma termos o controle da realização de refreshs nas páginas por parte dos usuários. Dennes Torres |
||||||||||||||||||||||||||||||||
|
Veja abaixo os comentários já enviados :
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Quer
saber mais?
Faça um curso na Búfalo Informática, Treinamento e Consultoria e Prepare-se para o Mercado! Veja o que a Búfalo tem para você. |
||||||||||||||||||||||||||||||||
© Búfalo Informática,
Treinamento e Consultoria -
Rua Álvaro Alvim, 37 Sala 920 - Cinelândia - Rio de Janeiro / RJ
Tel.: (21)2262-1368 (21) 9240-5134 (21) 9240-7281 e-Mail: contato@bufaloinfo.com.br