Rappel client avec implémentation de la validation, exemple

Mise à jour : novembre 2007

Dans un rappel client, une fonction de script client envoie une demande à la page Web ASP.NET, qui exécute ensuite une version abrégée de son cycle de vie normal pour traiter le rappel. Pour garantir que les événements de rappel proviennent de l'interface utilisateur attendue, vous pouvez valider les rappels. Lors de la validation des rappels, vous enregistrez un événement pour validation pendant le rendu de la page Web, puis validez l'événement pendant le rappel.

Remarque :

La validation d'événement aide à sécuriser votre application Web contre les publications fausses, mais ne protège pas contre les attaques par relecture. Un schéma de validation de l'événement plus complet doit prendre en considération les caractéristiques de votre application Web et les autorisations de l'utilisateur qui accède à ses ressources. Pour plus d'informations, consultez Sécurité des applications Web ASP.NET.

L'exemple abordé ici étend les Implémentation de rappel de client (C#), exemple et Implémentation de rappel de client (Visual Basic), exemple. Dans ces exemples, un contrôle ListBox nommé ListBox1 est un contrôle côté serveur qui affiche une liste de produits. Un élément <button> HTML (et non un contrôle serveur Button) exécute un rappel pour obtenir des informations sur l'inventaire du produit. L'exemple est étendu pour introduire des informations supplémentaires qui indiquent si un produit est en vente et autoriser l'affichage de ces informations pour les utilisateurs authentifiés uniquement. Un contrôle LoginView est utilisé avec le jeu de propriétés LoggedInTemplate pour afficher le contenu supplémentaire. Les utilisateurs anonymes de la page Web sont autorisés à exécuter un rappel pour obtenir des informations sur l'inventaire, alors que les utilisateurs connectés sont également autorisés à exécuter un rappel pour obtenir des informations sur les ventes. Le rappel pour les informations sur les ventes est enregistré pour la validation d'événement uniquement si l'utilisateur est authentifié. Cela empêche l'exécution du rappel par des utilisateurs qui ne sont pas authentifiés.

Exemple

Description

Dans l'exemple suivant, une page Web émule une recherche sur la base de données pour déterminer le nombre d'articles qui sont disponibles et si un article est en vente. Pour simplifier l'exemple, le magasin de données est représenté par deux listes de dictionnaires. Dans une application de production, on utiliserait plutôt une base de données. L'exemple illustre un scénario où la validation de rappels clients empêche un utilisateur anonyme d'exécuter un rappel qui est destiné uniquement aux utilisateurs authentifiés.

Code

<%@ 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);
    }
}

Commentaires

La page Web émule une consultation de base de données afin de déterminer le nombre d'articles disponibles, ou en réserve, pour une série de produits (écrans, claviers, etc.). Pour simplifier cet exemple de code, la base de données est représentée par une liste de dictionnaire qui contient un petit jeu d'articles. La clé de chacun des articles de la table est le nom de l'article (par exemple, écran), et sa valeur est le nombre d'articles en réserve. Dans une application de production, on utiliserait plutôt une base de données.

Lorsque la page s'exécute, un contrôle ListBox est lié à la table de hachage afin que le contrôle ListBox affiche la liste des produits. Pour les utilisateurs authentifiés, la page est rendue avec deux éléments <button> HTML dont les événements onclick sont liés à une fonction cliente nommée LookUpStock et une fonction cliente nommée LookUpSale, respectivement. Pour les utilisateurs anonymes, la page est rendue avec un seul élément <button> HTML dont l'événement onclick est lié à LookUpStock. Un contrôle LoginView est utilisé pour spécifier les boutons qui sont affichés. Dans un événement Render substitué pour la page, les boutons sont enregistrés pour la validation. Si l'utilisateur n'est pas authentifié, le bouton qui initialise le rappel pour LookUpSale n'est pas enregistré et la tentative de rappel échouera.

La page code-behind ajoute à la page le script côté client via la méthode RegisterClientScriptBlock. Le script ajouté à la page comprend une fonction nommée CallServer, laquelle obtient le nom de la méthode qui publiera sur le serveur à partir de la méthode GetCallbackEventReference.

Le rappel client appelle la méthode RaiseCallbackEvent pour déterminer la réserve disponible du produit qui lui a été passé. La méthode GetCallbackResult retourne la valeur. Notez que les arguments échangés entre le script client et le code serveur ne peuvent être que des chaînes. Pour passer ou recevoir plusieurs valeurs, vous pouvez concaténer des valeurs respectivement dans la chaîne d'entrée ou de retour.

Note de sécurité :

Si votre page Web et les rappels clients gèrent l'affichage de données sensibles ou d'opérations d'insertion, de mise à jour ou de suppression des données, il est recommandé de valider les rappels pour vous assurer que l'élément d'interface utilisateur prévu exécute le rappel.

Voir aussi

Tâches

Comment : implémenter des rappels dans des pages Web ASP.NET

Concepts

Implémentation par programme des rappels clients sans publication (postback) dans des pages Web ASP.NET

Implémentation de rappel de client (C#), exemple

Implémentation de rappel de client (Visual Basic), exemple

Référence

ClientScriptManager

RegisterForEventValidation

ValidateEvent