Em todos os sistemas web existem vários problemas que não são vistos pelos programadores e testers, e sim pelos usuários do sistema. Um dos problemas mais graves que acontece e que poucos conseguem perceber é quando um usuário clica duas vezes em um botão para gravar um registro no banco e o sistema acaba gravando duas vezes o mesmo registro. Este artigo descreve uma resolução simples e prática para aplicar em seu sistema .NET utilizando o Microsoft Visual Studio 2008 e um simples JavaScript.
Registro duplicado
A aplicação web é executada no servidor, a cada acesso o servidor processas a página solicitada e envia somente o HTML para o cliente. Cada vez que você clica em um botão a página dispara um evento que será processado no servidor que em seguida retorna a página toda para o cliente. Esse processo é chamado de POST. Por esse motivo todo POST que ocorre a página “pisca”.
Existe um tempo em que a página ainda fica em exibição no browser antes de piscar. Esse é o tempo em que a aplicação leva para enviar a requisição ao servidor, o servidor por sua vez processar a informação e retornar o HTML. E também existe outro tempo que o browser fica em branco, que é o tempo em que o HTML é renderizado no browser.
Quando o usuário clica uma vez e no botão a página envia a requisição ao servidor e ainda mostra a página, aí o usuário clica outra vez no botão e envia outra requisição ao browser. O servidor recebendo duas requisições irá gravar duas vezes o mesmo registro.
Solução
Para solucionar esse problema, criei um JavaScript que em todo POST é acrescentado um div na frente da página toda e enquanto esse div estiver aparecendo não dará outro POST. Assim bloqueia o usuário clicar duas vezes com o mouse ou mesmo apertar duas vezes a tecla enter. A diferença dessa solução apresentada para o UpdateProgress, recurso presente no Microsoft Ajax .NET, é que o UpdateProgress só atua no UpdatePanel enquanto essa solução do Aguarde atua em qualquer post da sua solução sem retrabalho em todas as páginas.
Então vamos ao que interessa. O código, seguindo os passos.
Crie um novo website no Visual Studio. Chamei a minha de TesteMSGAguarde.
Crie uma pasta chamada JS dentro do seu WebSite e nessa pasta adicione um novo arquivo JScript chamado MSGAguarde.js e adicione o seguinte código:
function avisoAguarde()
{
if(document.getElementById('divProcessando'))
{
document.getElementById('divProcessando').style.display='';
return;
}
oDiv = document.createElement("div");
with (oDiv)
{
id = "divProcessando";
}
document.body.appendChild(oDiv);
}
O código acima verifica se o div já existe, caso sim, o torna visível, caso não, cria um novo.
Agora crie um arquivo de classe no seu WebSite chamado BaseWebUi.cs (se seu site for em C#), cujo código será o seguinte:
public class BaseWebUi : System.Web.UI.Page
{
protected override void OnInit(EventArgs e)
{
//se o div de Aguarde ainda estiver mostrando ele tira
ScriptManager src = ScriptManager.GetCurrent(Page);
if (src != null)
ScriptManager.RegisterClientScriptBlock(
this,
typeof(void),
"TiraDivAguarde",
"if(document.getElementById('divProcessando'))
document.getElementById('divProcessando')
.style.display = 'none';",
true);
else
ClientScript.RegisterStartupScript(
typeof(Page),
"TiraDivAguarde",
"if(document.getElementById('divProcessando'))
document.getElementById('divProcessando')
.style.display = 'none';",
true);
ClientScript.RegisterOnSubmitStatement(
this.GetType(),
"zerarfiltro",
"if(document.getElementById('divProcessando') &&
document.getElementById('divProcessando')
.style.display!='none')return false;");
ClientScript.RegisterOnSubmitStatement(
this.GetType(),
"Aguarde",
"if (typeof(ValidatorOnSubmit) == 'function' &&
ValidatorOnSubmit() == false) return false; avisoAguarde();");
base.OnInit(e);
}
}
A classe herda da System.Web.UI.Page e sobrescreve o método OnInit (que é executado toda vez que a página é carregada). O método onInit chama a função javascript avisoAguarde() e impede o post se o divProcessando estiver na tela.
Agora é só referenciar o arquivo JS e adaptar o BaseWebUi à sua página. Abra o arquivo Default.aspx.cs (se seu site for em C#) e troque a herança de System.Web.Ui.Page para BaseWebUi.
Abra o arquio Default.aspx e entre as tags Head coloque a referência ao arquivo MSGAguarde.js, da seguinte forma:
<script type="text/javascript" src="js/MSGAguarde.js"></script>
Agora vamos dar um visual para o DIV como Theme. Crie um Asp.Net Folderdo tipo Theme, chamado MSG. Adicione uma pasta chamada Imagens em seu Theme MSG e nessa mesma pasta, copie um GIF animado com uma mensagem de aguarde de sua preferência. Em seguida adicione um novo arquivo CSS em seu Theme MSG. A estrutura de pastas deve ficar semelhante à Figura 1.
E escreva um Theme para o DIV que aparecerá na frente da tela a cada post. Neste exemplo foi utilizado o seguinte CSS:
#divProcessando
{
background: url(imagens/carregandopagina.gif) no-repeat center;
position:fixed;
z-index:99;
width:100%;
height:100%;
top:0;
left:0;
}
Adicione o Theme MSG para toda a sua aplicação. Abra o arquivo Web.Config e na tag adicione a propriedadetheme=”MSG”.
Pronto! Agora todo post que a sua página fizer irá aparecer a imagem de Aguarde.
Teste
Para testar nossa aplicação crie um botão do asp.net na Default.aspx e no evento Click, digite o seguinte código:
System.Threading.Thread.Sleep(1000);
O código serve para quando o evento Click do botão for acionado, o sistema espera um segundo, para efeito de emular um processamento mais longo. Execute a página e clique no botão e a seguinte mensagem aparecerá para avisar que o sistema está processando.
Um problema simples pode destruir um projeto. Essa solução é simples de implementar e funciona quando a página possui validators ou até mesmo Ajax, isso dá muito mais qualidade ao software. E lembre-se sempre, o cliente é fiel a qualidade e não à empresa.