Comment puis-je implémenter le post-redirect-get motif avec asp.net?
Un bouton clic sur effectue un certain traitement:
<asp:Button id="bbLaunch" OnCommand="bbLaunch_Click" />
L'utilisateur clique sur le bouton, le vaisseau spatial est lancé, la page Web réaffiche. Si l'utilisateur appuie sur F5, ils obtiennent l'avertissement:
La solution au problème est le post-redirect-get motif.
Quelle est la méthode par laquelle [~ # ~ # ~] prg [~ # ~ ~] peut être implémenté dans ASP.NET?
Les centres de questions autour des problèmes de:
<asp:Button>
exécutera-t-il un POST
à un endroit qui n'est pas sa forme originale?Response.Redirect(Request.RawUrl);
Server.Transfer
. L'utilisation de Server.Transfer
est complètement fausse et ne résout en aucun cas le problème post-redirect-obtenir (car il n'y a pas Rediriger). Correct?aspx
ou aspx.cs
pour supporter le PRG? Vraisemblablement, à tout le moins, le code doit être remplacé par post
quelque part en plus de MyPage.aspx
.En d'autres termes: Comment faites-vous post-redirection-get in asp.net?=
Note: ASP.NET (c'est-à-dire pas ASP.NET MVC)
Généralement, vous le feriez en faisant un formulaire Web ASPX qui utilise le requérant pour signaler quel enregistrement pour charger/traiter.
Disons que vous avez une page qui vous permet de mettre à jour des informations client:
http://www.mysite.com/customer.aspx
Vous chargeriez le formulaire à l'aide d'un identifiant dans la QueryString:
http://www.mysite.com/customer.aspx?CustomerId=42
Dans le codebehind, vous auriez quelque chose comme ça:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
int customerId = 0;
if (!string.IsNullOrEmpty(Request.QueryString["CustomerId"]))
{
int.TryParse(Request.QueryString["CustomerId"], out customerId );
}
if (customerId == 0)
{
//handle case when no valid customer id was passed in the qs here
}
else
{
//load customer details, bind controls etc
//make sure to handle the case when no customer was found using the id in the qs
}
}
}
Ensuite, quelque part dans votre page, vous auriez un bouton qui enregistre les modifications. Ce bouton aurait un gestionnaire oncelick dans le code derrière:
protected void SaveClicked(object sender, EventArgs e)
{
//save changes to database here
//Redirect if all went well
Response.Redirect("http://www.mysite.com/customer.aspx?CustomerId="
+ idOfSavedCustomer.ToString());
}
Cela devrait fondamentalement être. La redirection provoquera le navigateur d'émettre une nouvelle demande d'obtention de l'URL dans la redirection (...). Il chargera la page, la fonction if (!IsPostBack)
exécutera et initialisera la page avec les nouvelles valeurs que vous venez d'enregistrer dans le post précédent.
Pour tout ce processus, le trafic entre navigateur et serveur ressemblerait à ceci comme suit:
Browser: GET http://www.mysite.com/customer.aspx?CustomerId=42
Server: 200 (send back some html)
Browser: POST http://www.mysite.com/customer.aspx?CustomerId=42 (post data sent in request)
Server: 302 (point to http://www.mysite.com/customer.aspx?CustomerId=42)
Browser: GET http://www.mysite.com/customer.aspx?CustomerId=42
Server: 200 (send html)
Au niveau moyen, le serveur dit essentiellement:
"Cette demande postale que vous m'avez envoyée, j'ai fini avec ça. Maintenant, veuillez vous rendre à cette autre page ici ..."
Le fait que l'URL fait en effet référence à la même page n'est pas importante.
Quelques références en réponse à la liste de questions de votre point balle:
Vous pouvez le faire en définissant l'attribut action
sur le formulaire ou vous pouvez définir le bouton PostBackUrl
sur le bouton.
Dépend. Si vous publiez simplement le formulaire sur une autre page, vous pouvez utiliser la <% @ précédentPageType ... /> la directive pour indiquer à la page "Nouvelle" page où est venu le poste. Cela permettra simplement de travailler avec les données postées sur la nouvelle page. Voir Ce lien pour plus de détails .
Afficher l'état est envoyé dans la demande postale. Lors de la redirection, le navigateur chargera une nouvelle page et créera son propre vieste.
Cela dépend de la façon dont vous le regardez. Après la redirection, la nouvelle page n'aura pas accès à la vision de la page avant.
Non, voir exemple ci-dessus.
Réponse.redirect (URL). Cela enverra une réponse au navigateur, en lui disant de faire une nouvelle demande d'obtention.
Lorsque vous avez effectué tout le travail nécessaire pour traiter la demande postale.
La redirection d'une demande postale n'est pas bien prise en charge et devrait probablement être évitée. Il peut être fait (avec un navigateur) à l'aide de la réponse HTTP 307. Lorsque cela le faisait, le serveur indique efficacement au navigateur que " Je ne traiterai pas votre demande postale, veuillez le poster à cette question. autre page à la place ".
Server.Transfer (...) est quelque chose qui se produit sur le côté serveur. Le navigateur n'est pas au courant. Fondamentalement, une page peut utiliser Server.Transfer pour que Som Autre page effectue un certain traitement et que cette page sera responsable de l'envoi d'une réponse au navigateur. Mais le navigateur pensera que c'était la page d'origine de la réponse.
Non, un dos régulier peut être utilisé. L'astuce consiste à avoir un (ou quelques-uns) gestionnaire d'événements spécifique sur la page qui fait une répétation.redirect après traitement des données affichées.
Q) Comment l'exécution A POST à un endroit n'est-elle pas sa forme originale?
A) avec PRG, vous n'avez pas POST sur une page différente, vous postez à la même page (voir le diagramme de la page Wikipedia que vous avez liée.) Mais la réponse de cette page Doit être une réponse de 30x (typiquement un 302.)
Q) Qu'est-ce qui devient de la vieillissement lorsque vous postez un formulaire qui n'a pas lu l'état de vue?
A) L'état d'affichage est là lorsque vous postez, mais là l'état d'affichage ne sera pas là pour la nouvelle page que vous effectuez.
Q) Qu'est-ce qui devient de la viefstate lorsque vous redirigez vers le formulaire Web Aspx "réel"?
A) Perform, il n'ya plus d'état d'affichage redirige vers la page.
Q) Viewstate est-il fondamentalement incompatible avec ASP.NET?
A) Viewstate n'est pas incompatible avec ASP.NET. Il est (principalement) inutile pour P/R/G d'avoir rendu la page que vous êtes redirigé.
Q) L'ASP.NET est-il fondamentalement incompatible avec la post-redirection - obtenir?
A) Non - mais vous ne pouvez pas trop compter sur l'utilisation d'une page et conservez tout votre état dans la vieillette, comme ci-dessus. Cela dit, ASP.MVC est une carte beaucoup mieux pour p/r/g
Q) Comment (c'est-à-dire quel code) vérifiez-vous vers le formulaire Web ASPX "réel"?
A) réponse.redirect ("new_page_you_are_redirecting_to.aspx") dans la méthode bblaunch_click de old_page_you_are_posting_from.aspx
Q) Comment (c'est-à-dire quelle URL) redirige-vous au formulaire Web ASPX "réel"? Une question de relation mentionne la réponse.redirect (demande.rawurl);
A) voir ci-dessus
Q) Quand (c'est-à-dire dans quel gestionnaire d'événement) Redirigerez-vous vers le formulaire Web ASPX "réel"?
A) Une fois que vous avez traité le bouton, appuyez sur, enregistré les données sur DB (ou Session, etc.), et avant d'avoir écrit autre chose au flux de réponses.
Q) Les questions connexes soulèvent des problèmes de la manière dont vous postez des données de formulaire. Il y a l'implication que les formes HTML ne peuvent pas être utilisées - et toutes les données de formulaire doivent être ajoutées à la chaîne de requête. Est-ce vrai?
A) NON - Le bouton Appuyez sur ASP.NET WebForms Will POST Retour à la page.
Q) Si oui, pourquoi? Sinon, pourquoi pas?
A) C'est plus simple que cela, c'est pourquoi pas. Imagerie deux pages: first_page.asp et second_page.aspx. First_page.aspx a le bouton sur celui-ci (avec d'autres commandes Web ASP.NET, telles que les zones de texte, etc. que l'utilisateur a rempli.) Lorsqu'ils appuient sur le bouton, A POST est fait à first_page.aspx. Après le traitement des données (qui est probable à l'intérieur de la vietatée, bien que cela soit abstraité), vous redirigez l'utilisateur sur second_page.aspx à l'aide de réponse.redirect. second_page.aspx peut afficher ce que vous voulez. Si vous voulez ( ou besoin) pour afficher l'interface utilisateur similaire à ce qui était sur le premier_page.aspx, y compris les contrôles et ce qu'ils ont saisi, vous souhaitez stocker cela dans la session, un cookie, l'URL comme QueryString paramètres, pour définir ces contrôles sur second_page .aspx. (Mais vous n'avez peut-être pas besoin d'afficher quoi que ce soit sur second_page.aspx qui est similaire à first_page.aspx - il n'y a donc aucune règle générale ici.)
Q) Un navigateur peut-il mettre des données de formulaire dans une chaîne de requête?
A) Oui, si vous définissez la méthode pour obtenir au lieu de poster. Vous ne pouvez pas remplacer WebForms pour le faire, et ce n'est pas nécessaire pour PRG
Q) une question connexe mentionne Server.Transfer. Utiliser Server.Transfer est complètement faux et ne résout en aucun cas le problème post-redirect-obtenir (car il n'y a pas de redirection). Correct?
A) essentiellement
Q) Quel changement de code doit-il se produire dans le fichier ASPX ou ASPX.CS pour soutenir PRG? Vraisemblablement, à tout le moins, le code doit être changé pour poster quelque part en plus de MyPage.aspx.
A) Le code devrait encore poster (comme mentionné ci-dessus.) Mais alors mypage.aspx doit rediriger vers une nouvelle page du gestionnaire de bouton.
Le motif post-redirect-get peut être utilisé sur des formulaires Web. J'ai montré comment cela peut être fait en convertissant l'application MVC NERDDINNER en formulaires Web, http://navatednerddinner.codeplex.com/ . J'ai gardé les détails de la navigation exactement la même chose, donc il y a beaucoup d'exemples du modèle PRG.
Cependant, il existe une autre façon d'éviter le problème F5/Rafraîchir. Si vous enveloppez votre page dans un Panneau UpdatePanel (partie d'ASP.NET AJAX), tous les dos de poste seront convertis en demandes de page partielle. Cela signifie que lorsque F5 est enfoncé, il ne vous rafraîchira que la demande d'origine d'origine (puisqu'il n'avait pas été des messages suivants), et vous n'obtiendrez donc pas l'avertissement. (Remarque, si JavaScript est désactivé, l'avertissement apparaîtra encore).
Les étapes exactes du post redirigent-elles sont celle-ci:
Vous avez la forme que vous avez remplie avec des données et après votre soumission valide (poste), vous les insérez dans votre base de données et donnez-leur un identifiant de confirmation, puis vous redirigeez l'utilisateur sur la page avec cet identifiant de confirmation en tant que paramètre URL utilisé. Comme le (obtenez) après la redirection, chaque rafraîchissement F5 est seulement lisez les données et ne les insérez pas à nouveau.
Le code d'insertion est différent du code indiquant la confirmation, vous pouvez même les créer différentes pages - vous pouvez créer la même page avec des zones de texte en lecture seule.
La redirection est simple le Responce.Redirect
fonction d'asp.net
Après le POST et la création de la redirection, la seule pensée que vous connectez à l'action précédente est le code de confirmation (pas la vue de la vue)
Le moins de cette méthode est que ce qui est en fait ne reconnaît pas l'actualisation, il suffit de faire une étape supplémentaire qui rend l'actualisation ne pas insérer à nouveau les mêmes données - mais nécessite un code supplémentaire pour obtenir des données.
L'alternative est de reconnaître l'actualisation et de ne pas faire de la redirection. En reconnaissant l'actualisation sur la post-retour, vous pouvez éviter d'insérer les mêmes données avec un seul message à l'utilisateur. Il existe quelques exemples sur Internet pour cela, et j'ai mis en œuvre un avec succès.
Un exemple: http://www.codeproject.com/tips/319955/how-to-prevent-re-post-action-caused-by-pressing-b
Vous pouvez invoquer la méthode réponse.redirect pour aller à un autre endroit.
Il y a quelques choses qui vont dans cela.
Définir le action Attribut du formulaire sur la page principale (appelons-le landeform.aspx) égal à l'URL de la page "Proxy" (Proxylaunchform.aspx).
<formulaire id = "form1" runat = "serveur" action = "proxylaunchform.aspx" méthode = "post">
(Facultatif) Ajoutez une entrée cachée avec le nom redirecturl au formulaire et valorisez l'URL qui indique proxylaunchform.aspx Où rediriger une fois que la redirection est terminée. lancement (le rôle de PRG).
Maintenant sur proxylaunchform.aspx, la mise en œuvre devrait avoir lieu à l'intérieur de la Page_load gestionnaire d'événements, car cela a accès à des données post-formes. Exécuter le lancement ici.
Par la suite (aussi dans Page_load), effectuez la redirection (en utilisant le redirecturl de # 2 ou simplement à l'aide de l'URL de la page de référification):
Réponse.redirect (demande.params ["redirecturl"] ?? demande.urlreferrer.absolantsuri);
Il y a toujours la question de l'état d'affichage. Je pense que le moyen le plus simple de traiter cela est de changer comment l'état de vue est persisté. Normalement, il est enregistré dans un élément d'entrée caché de la page et récupéré sur le post-plan (ce qui signifie bien sûr qu'il serait perdu après la redirection due à la nature apatride de HTTP). Toutefois, vous pouvez remplacer les méthodes que ASP.NET utilise et l'avoir utilisée Session à la place (de cette façon, il sera toujours présent même après l'action de proxy PRG). Alors, enfin ...
In LaunchForm.aspx.cs, utilisez comme classe de base A sous-classée page qui remplace le sauvegarde de sauvegarde du fichier et LoLoardPagestatefrompSisticAncemedium Méthodes pour stocker/les récupérer de la session, plutôt que d'un champ de formulaire caché. Voir ci-dessous (et voici plus d'informations sur la façon dont cela fonctionne. ).
*
public class PersistViewStateToSession : Page
{
protected override void SavePageStateToPersistenceMedium(object viewState)
{
// serialize the view state into a base-64 encoded string
LosFormatter los = new LosFormatter();
StringWriter writer = new StringWriter();
los.Serialize(writer, viewState);
// save the string to session
Session["LaunchViewState"] = writer.ToString();
}
protected override object LoadPageStateFromPersistenceMedium()
{
if (!Session["LaunchViewState"] == null)
return null;
else
{
string sessionString = (string)Session["LaunchViewState"];
// deserialize the string
LosFormatter los = new LosFormatter();
return los.Deserialize(viewStateString);
}
}
}