Retorno de chamada de cliente com exemplo de implementação de validação
Em um retorno de chamada do cliente, uma função script de cliente envia uma solicitação para a página da Web do ASP.NET, que, em seguida, executa uma versão abreviada do seu ciclo de vida normal para processar o retorno de chamada.Para garantir que os eventos de retorno de chamada originem da interface do usuário (IU) esperada, você pode validar retornos de chamada.Validação de retorno de chamada envolve registrar um evento para validação durante o processamento página da Web e, em seguida, validar o evento durante o retorno de chamada.
Observação: |
---|
Validação de evento ajuda a proteger seu aplicativo da Web contra postagens forjadas mas não protege contra ataques de repetição.Um esquema de validação de evento mais abrangente deve levar em consideração as especificidades do seu aplicativo da Web e as permissões do usuário que acesse seus recursos.Para obter mais informações, consulte Segurança de aplicativos da Web ASP.NET. |
O exemplo discutido aqui estende o Exemplo de implementação (C#) callback de cliente e o Exemplo de Implementação (Visual Basic) da Chamada de Retorno do Cliente.Nesses exemplos, um controle ListBox chamado ListBox1 é um controle do lado do servidor que exibe uma lista de produtos.Um elemento <button> HTML (não um controle de servidor Button) executa um retorno de chamada para obter informações de inventário do produto.O exemplo é estendido para apresentar informações adicionais sobre se um produto está à venda e para permitir que essa informação seja visualizada somente por usuários autenticados.Um controle LoginView é usado com a propriedade LoggedInTemplate definida para exibir conteúdo adicional.Usuários anônimos do página da Web podem executar um retorno de chamada para obter informações de inventário, enquanto usuários conectados também têm permissão para executar um retorno de chamada para obter informações de venda.O retorno de chamada para as informações de venda informações é registrado para eventos de validação somente se o usuário estiver autenticado.Isso impede a execução do retorno de chamada por usuários que não estão autenticados.
Exemplo
Descrição
No exemplo a seguir, um página da Web emula uma pesquisa de banco de dados para determinar o número de itens que estão disponíveis e se um item está à venda.Para simplificar o exemplo, o armazenamento de dados é representado por duas listas de dicionário.Em um aplicativo comercial, um banco de dados deve ser usado em vez disso.O exemplo demonstra um cenário onde retornos de chamada de validação de cliente impede um usuário anônimo de executar um retorno de chamada que se destina somente a usuários autenticados.
Código
<%@ Page Language="VB" AutoEventWireup="false"
CodeFile="ClientCallback.aspx.vb" Inherits="ClientCallback" %>
<!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" >
<title>ASP.NET Example</title>
<script type="text/javascript">
function ReceiveServerData(rValue)
{
Results.innerText = rValue;
}
</script>
</head>
<body>
<form id="form1" >
<div>
<asp:ListBox id="ListBox1" ></asp:ListBox>
<br />
<br />
<button id="LookUpStockButton" onclick="LookUpStock()">Look Up Stock</button>
<asp:LoginView id="LoginView1" >
<LoggedInTemplate>
<button id="LookUpSaleButton" onclick="LookUpSale()">Look Up Back Order</button>
</LoggedInTemplate>
</asp:LoginView>
<br />
Item status: <span id="Results"></span>
</div>
</form>
</body>
</html>
<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="ClientCallback.aspx.cs" Inherits="ClientCallback" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML
1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" >
<title>ASP.NET Example</title>
<script type="text/javascript">
function ReceiveServerData(rValue)
{
Results.innerText = rValue;
}
</script>
</head>
<body>
<form id="form1" >
<div>
<asp:ListBox id="ListBox1" ></asp:ListBox>
<br />
<br />
<button id="LookUpStockButton" onclick="LookUpStock()">Look Up Stock</button>
<asp:LoginView id="LoginView1" >
<LoggedInTemplate>
<button id="LookUpSaleButton" onclick="LookUpSale()">Look Up Back Order</button>
</LoggedInTemplate>
</asp:LoginView>
<br />
Item status: <span id="Results"></span>
</div>
</form>
</body>
</html>
Partial Class ClientCallback
Inherits System.Web.UI.Page
Implements System.Web.UI.ICallbackEventHandler
Protected catalog As ListDictionary
Protected saleitem As ListDictionary
Protected returnValue As String
Protected validationLookUpStock As String = "LookUpStock"
Protected validationLookUpSale As String = "LookUpSale"
Sub Page_Load(ByVal sender As Object, ByVal e As _
System.EventArgs) Handles Me.Load
Page.ClientScript.RegisterClientScriptBlock(Me.GetType(), _
validationLookUpStock, "function LookUpStock() { " & _
"var lb = document.forms[0].ListBox1; " & _
"var product = lb.options[lb.selectedIndex].text; " & _
"CallServer(product, ""LookUpStock"");} ", True)
If (User.Identity.IsAuthenticated) Then
Page.ClientScript.RegisterClientScriptBlock(Me.GetType(), _
validationLookUpSale, "function LookUpSale() { " & _
"var lb = document.forms[0].ListBox1; " & _
"var product = lb.options[lb.selectedIndex].text; " & _
"CallServer(product, ""LookUpSale"");} ", True)
End If
Dim cbReference As String
cbReference = "var param = arg + '|' + context;" & _
Page.ClientScript.GetCallbackEventReference(Me, _
"param", "ReceiveServerData", "context")
Dim callbackScript As String = ""
callbackScript &= "function CallServer(arg, context) { " & _
cbReference & "} ;"
Page.ClientScript.RegisterClientScriptBlock(Me.GetType(), _
"CallServer", callbackScript, True)
' Populate List Dictionary with invented database data
catalog = New ListDictionary()
saleitem = New ListDictionary()
catalog.Add("monitor", 12)
catalog.Add("laptop", 10)
catalog.Add("keyboard", 23)
catalog.Add("mouse", 17)
saleitem.Add("monitor", 1)
saleitem.Add("laptop", 0)
saleitem.Add("keyboard", 0)
saleitem.Add("mouse", 1)
ListBox1.DataSource = catalog
ListBox1.DataTextField = "key"
ListBox1.DataBind()
End Sub
Public Sub RaiseCallbackEvent(ByVal eventArgument As String) _
Implements System.Web.UI.ICallbackEventHandler.RaiseCallbackEvent
Dim argParts() As String = eventArgument.Split("|"c)
If ((argParts Is Nothing) OrElse (argParts.Length <> 2)) Then
returnValue = "A problem occurred trying to retrieve stock count."
Return
End If
Dim product As String = argParts(0)
Dim validationaction = argParts(1)
Select Case validationaction
Case "LookUpStock"
Try
Page.ClientScript.ValidateEvent("LookUpStockButton", validationaction)
If (catalog(product) Is Nothing) Then
returnValue = "Item not found."
Else
returnValue = catalog(product).ToString() & " in stock."
End If
Catch
returnValue = "Can not retrieve stock count."
End Try
Case "LookUpSale"
Try
Page.ClientScript.ValidateEvent("LookUpSaleButton", validationaction)
If (saleitem(product) Is Nothing) Then
returnValue = "Item not found."
Else
If (Convert.ToBoolean(saleitem(product))) Then
returnValue = "Item is on sale."
Else
returnValue = "Item is not on sale."
End If
End If
Catch
returnValue = "Can not retrieve sale status."
End Try
End Select
End Sub
Public Function GetCallbackResult() _
As String Implements _
System.Web.UI.ICallbackEventHandler.GetCallbackResult
Return returnValue
End Function
Protected Overrides Sub Render(ByVal writer As System.Web.UI.HtmlTextWriter)
Page.ClientScript.RegisterForEventValidation("LookUpStockButton", _
validationLookUpStock)
If (User.Identity.IsAuthenticated) Then
Page.ClientScript.RegisterForEventValidation("LookUpSaleButton", _
validationLookUpSale)
End If
MyBase.Render(writer)
End Sub
End Class
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
public partial class ClientCallback : System.Web.UI.Page,
System.Web.UI.ICallbackEventHandler
{
protected System.Collections.Specialized.ListDictionary catalog;
protected System.Collections.Specialized.ListDictionary saleitem;
protected String returnValue;
protected String validationLookUpStock = "LookUpStock";
protected String validationLookUpSale = "LookUpSale";
protected void Page_Load(object sender, EventArgs e)
{
Page.ClientScript.RegisterClientScriptBlock(this.GetType(),
validationLookUpStock, "function LookUpStock() { " +
"var lb = document.forms[0].ListBox1; " +
"var product = lb.options[lb.selectedIndex].text; " +
@"CallServer(product, ""LookUpStock"");} ", true);
if (User.Identity.IsAuthenticated)
{
Page.ClientScript.RegisterClientScriptBlock(this.GetType(),
validationLookUpSale, "function LookUpSale() { " +
"var lb = document.forms[0].ListBox1; " +
"var product = lb.options[lb.selectedIndex].text; " +
@"CallServer(product, ""LookUpSale"");} ", true);
}
String cbReference = "var param = arg + '|' + context;" +
Page.ClientScript.GetCallbackEventReference(this,
"param", "ReceiveServerData", "context");
String callbackScript;
callbackScript = "function CallServer(arg, context)" +
"{ " + cbReference + "} ;";
Page.ClientScript.RegisterClientScriptBlock(this.GetType(),
"CallServer", callbackScript, true);
catalog = new System.Collections.Specialized.ListDictionary();
saleitem = new System.Collections.Specialized.ListDictionary();
catalog.Add("monitor", 12);
catalog.Add("laptop", 10);
catalog.Add("keyboard", 23);
catalog.Add("mouse", 17);
saleitem.Add("monitor", 1);
saleitem.Add("laptop", 0);
saleitem.Add("keyboard", 0);
saleitem.Add("mouse", 1);
ListBox1.DataSource = catalog;
ListBox1.DataTextField = "key";
ListBox1.DataBind();
}
public void RaiseCallbackEvent(String eventArgument)
{
string[] argParts = eventArgument.Split('|');
if ((argParts == null) || (argParts.Length != 2))
{
returnValue = "A problem occurred trying to retrieve stock count.";
return;
}
string product = argParts[0];
string validationaction = argParts[1];
switch (validationaction)
{
case "LookUpStock":
try
{
Page.ClientScript.ValidateEvent("LookUpStockButton", validationaction);
if (catalog[product] == null)
{
returnValue = "Item not found.";
}
else
{
returnValue = catalog[product].ToString() + " in stock.";
}
}
catch
{
returnValue = "Can not retrieve stock count.";
}
break;
case "LookUpSale":
try
{
Page.ClientScript.ValidateEvent("LookUpSaleButton", validationaction);
if (saleitem[product] == null)
{
returnValue = "Item not found.";
}
else
{
if (Convert.ToBoolean(saleitem[product]))
returnValue = "Item is on sale.";
else
returnValue = "Item is not on sale.";
}
}
catch
{
returnValue = "Can not retrieve sale status.";
}
break;
}
}
public String GetCallbackResult()
{
return returnValue;
}
protected override void Render(HtmlTextWriter writer)
{
Page.ClientScript.RegisterForEventValidation("LookUpStockButton",
validationLookUpStock);
if (User.Identity.IsAuthenticated)
{
Page.ClientScript.RegisterForEventValidation("LookUpSaleButton",
validationLookUpSale);
}
base.Render(writer);
}
}
Comentários
A página da Web emula uma pesquisa de banco de dados para determinar o número de itens que estão disponíveis, ou em estoque, para uma série de produtos (monitores, teclados, e assim por diante).Para simplificar este exemplo de código, o banco de dados é representado por uma lista dicionário que contém um conjunto pequeno de itens.Para cada item na tabela, a chave é o nome do item (como monitor) e o valor é o número de itens que estão em estoque.Em um aplicativo comercial, um banco de dados deve ser usado em vez disso.
Quando a página é executada, um controle ListBox é vinculado à tabela de hash para que o controle ListBox exiba a lista de produtos.Para usuários autenticados, a página é processada com dois elementos <button> HTML cujos eventos onclick são vinculados a uma função do cliente chamado LookUpStock e uma função do cliente chamado LookUpSale, respectivamente.Para usuários anônimos, a página é processada com apenas um elemento <button> HTML, cujo evento onclick evento está vinculado a LookUpStock.Um controle LoginView é usado para especificar quais botões são mostrados.Em um evento Render substituído para a página, os botões são registrados para validação.Se o usuário não for autenticado, o botão que inicia o retorno de chamada para LookUpSale não é registrado e o retorno de chamada falhará se ela for tentada.
A página code-behind adiciona script do lado do cliente para a página através do método RegisterClientScriptBlock.O script que é adicionado à página inclui uma função chamada CallServer, que obtém o nome do método que irá postar de volta para o servidor do método GetCallbackEventReference.
O retorno de chamada do cliente chama o método RaiseCallbackEvent, para determinar o estoque disponível para o produto passado para ele.O método GetCallbackResult retorna o valor.Observe que os argumentos enviados entre o script de cliente e o código do servidor só pode ser sequências.Para passar ou receber vários valores, você pode concatenar valores na sequência de caracteres de entrada ou de retorno, respectivamente.
Observação de segurança: |
---|
Se seus retornos de chamada de página da Web e de cliente lidam com a exibição de dados confidenciais ou operações que insiram, atualizem ou excluam dados, é recomendável que você valide retornos de chamada para garantir que o pretendido elemento de interface do usuário esteja executando o retorno de chamada. |
Consulte também
Tarefas
Como: Implementar Callbacks em páginas da Web do ASP.NET
Conceitos
Implementando Callbacks de Clientes Através de Programação Sem Postbacks nas Páginas ASP.NET
Exemplo de implementação (C#) callback de cliente
Exemplo de Implementação (Visual Basic) da Chamada de Retorno do Cliente