2010-02-16 4 views
1

Je pourrais voir, moi-même et beaucoup de gens ont des problèmes avec ces deux éléments dans ASP.NET ... Refresh Button, Back Button ... (Je vois beaucoup de gens sont allés à la demande de demander comment désactiver ces deux boutons dans le navigateur ..)Pourquoi ne pas implémenter 'IsRefresh', 'IsBackPost' comme 'IsPostBack'?

Maintenant, quels sont les problèmes dans l'implémentation de deux autres variables booléennes dans Page (IsRefresh, IsPostBack) ... Si ces problèmes peuvent être contournés et mis en œuvre, ce serait un atout majeur pour les développeurs ... Lorsque vous répondez, vous pouvez également inclure les étapes que vous effectuez dans votre application Web afin d'éviter de la replanter (parfois dans la base de données) dans des scénarios qui seraient utiles.

Merci

+1

connexes: http://stackoverflow.com/questions/1791416/prevent-postback-when-user-clicks-browsers-back-button –

Répondre

4

Le problème avec la mise en œuvre des deux propriétés booléennes supplémentaires est, qu'il n'y a vraiment pas (fiable) moyen de distinguer Retour/Actualiser suscité des demandes. Lorsque vous frappez sur ces boutons, le navigateur soit:

  1. afficher la page du cache si on les laisse, ou
  2. exécuter à nouveau la même demande exacte (peut-être demander à l'utilisateur de confirmer d'abord)

Vous rencontrez le cas # 2. Lorsque la deuxième demande se produit, le serveur recevra les exactes mêmes données de demande comme il le faisait avec la demande d'origine. Ainsi, ASP.NET (et la plupart des autres frameworks) gérera la requête tout comme l'original a été géré.Il y a plusieurs façons de contourner ce problème:

  1. changer votre politique de mise en cache pour permettre au navigateur de réafficher les résultats des demandes précédentes (peut résoudre le Retour problème, mais pas Actualiser).
  2. Ajoutez un champ masqué (ou des données dans ViewState) contenant une valeur unique sur la page à partir de laquelle les publications sont attendues. Ajoutez ensuite une structure de données pour conserver une liste de valeurs «utilisées», ainsi qu'une logique pour tester les doublons avant de faire quoi que ce soit de critique.
  3. Utilisez le Post/Redirect/Get pattern pour vous assurer que la demande POST ne se retrouve jamais dans l'historique du navigateur.

La solution 3 est facile à utiliser et fonctionne dans presque tous les cas. En fait, plutôt que de renvoyer les résultats/confirmation en réponse à la « critique » postback, faire une redirection vers une nouvelle URL:

protected void btnCritical_Click(object sender, EventArgs e) 
{ 
    DoSomethingThatShouldNotBeDoneTwice(); 
    Response.Redirect("confirmation.aspx"); 
} 
1

Ce n'est pas tout à fait aussi clair. La seule façon pour le serveur d'identifier un "PostBack" est basée sur les en-têtes transmis à la page par votre requête. Lorsque vous POSTEZ un formulaire, "IsPostBack" est vrai, comme vous vous y attendiez. Lorsque vous actualisez une page ou appuyez sur Retour, les mêmes données de demande sont envoyées. L'application ne peut pas détecter que l'utilisateur a émis une requête non standard (Retour ou Actualisation) sans modifier le comportement du navigateur qui envoie la demande.

Comme vous le savez, la plupart des navigateurs vous indiqueront que "Cliquer sur Retour renverra les données de formulaire ...", mais c'est simplement un avertissement émis par le navigateur pour vous faire savoir qu'il va envoyer l'exact même demande encore. Le serveur ne le sait pas et n'a aucun moyen (natif) d'interpréter l'information.

Double Postback Conseils de prévention

Une façon d'éviter que des données s'affichés deux fois est de faire en sorte que chaque publication contient des données uniques que vous pouvez valider. Le processus est assez simple.

Lors de chaque chargement de page, vous souhaiterez créer un identifiant unique pour les événements PostBack de cette page. Peu importe l'identifiant unique, tant que ce n'est pas la même chose pour les chargements de pages séquentiels. Placez cet identifiant unique dans un champ caché sur votre page ET dans la session de l'utilisateur (ou un cookie). Ensuite, sur chaque PostBack, validez que le cookie dans le champ caché correspond à la valeur de la session. Si les valeurs correspondent au PostBack, il s'agit d'un post original sur la page qui peut être traité en conséquence. Après avoir effectué les opérations nécessaires, vous devrez à nouveau modifier l'identifiant unique dans les deux emplacements. De cette façon, si l'utilisateur doit revenir en arrière et choisir de "Renvoyer les données", le champ masqué ne correspondra pas à la clé de session et vous pouvez rejeter les données de publication en double.

+0

Je voudrais (lire aussi désespérée) savoir, quelles mesures dois-je prendre, dans de tels scénarios, afin d'éviter une autre exécution d'appel/commande dans la base de données ... Un exemple classique serait une page où l'utilisateur entre des commentaires ... Hitting refresh insère le commentaire encore, et il serait difficile de vérifier si le même commentaire est déjà entré car le commentaire est long et il y a une possibilité que le même commentaire ait pu être valablement entré. –

+0

@The King: C'est facile. Après avoir ajouté le commentaire à la base de données, vous envoyez un Response.Redirect à la même page. Ensuite, lorsque l'utilisateur actualise ou revient en arrière, aucun commentaire ne sera ajouté à nouveau. –

+0

Ou cela fonctionne aussi. Simple et élégant. –

1

aspnet_isapi reconnaît une publication du contenu de forme, en particulier le champ ViewState. Il n'a aucun moyen intrinsèque de distinguer une publication d'un rafraîchissement. J'ai vu quelques stratégies pour travailler avec cela par le passé. La première est d'assigner un guid à chaque requête et de l'utiliser comme une clé ou un index unique dans la table que vous écrivez.

Vous pouvez créer une page de base dont toutes vos pages héritent.

public partial class PageBase : System.Web.UI.Page 
{ 
    private Guid _requestId; 

    protected Guid RequestId 
    { 
     get 
     { 
      return _requestId; 
     } 
    } 
    protected virtual void Page_Load(object sender, EventArgs e) 
    { 
     if (!IsPostBack) 
     { 
      _requestId = Guid.NewGuid(); 
      ViewState.Add("requestId", _requestId); 
     } 
     else 
     { 
      _requestId = (Guid)ViewState["requestId"]; 
     } 
    } 
} 

public partial class _Default : PageBase 
{ 
    protected override void Page_Load(object sender, EventArgs e) 
    { 
     base.Page_Load(sender, e); 

     // now do stuff 
    } 
} 
+0

oui, vous pouvez utiliser ceci pour implémenter la suggestion de jorn de garder la trace des demandes 'utilisées'. –

Questions connexes