__doPostBack and the Back Button
One of my West Wind Web Connection customers (but this also applies to ASP.NET) recently posted a question regarding a page that wasn't working correctly when using the Back button. The behavior would be something like this:
- Go to the page
- Click a link that causes a __doPostBack() to occur
- Click the Back button
- Click on a regular Submit button
What happens is that the Submit ends up re-executing the __doPostBack() operation, rather than firing the button click.
It's interesting, because I'd seen this behavior before myself but have never been able to put my finger on what actually causes the behavior and John happened to see the relation.
So, I'm not 100% sure why this happens but after a bit of tracing I do know that what happens is the following:
- __doPostBack event is fired against the server
- Server responds and updates the page appropriately
- Server generates the __EVENTxxxx hidden fields as empty values (correct behavior)
- Back button goes back to the previous page - page is not reloaded from server!
- Browser assigns __EVENTxxx etc. with the previous POST back values
- Button submit bypassess __doPostBack() and so the special vars are posted to the server
- The server detects the __EVENTxxxx form vars and routes events accordingly (incorrect behavior)
When I first saw this I figured this is a bug in my West Wind Web Connection framework code, but I was totally able to duplicate this in ASP.NET where the same behavior occurs.
You can see this behavior with a simple test form:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Postback.aspx.cs" Inherits="Test.Postback" EnableViewstate="True" %> <!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 runat="server"> <title>Untitled Page</title> <link href="Westwind.css" rel="stylesheet" type="text/css"> </head> <body> <form id="form1" runat="server"> <a href="Postback.aspx">Reload</a> <br /> <br /> <asp:TextBox ID="txtName" runat="server"></asp:TextBox> <asp:Button ID="btnSubmit" runat="server" Text="Button" onclick="btnSubmit_Click"></asp:Button> <br /> <asp:CheckBox ID="chkAutoPostback" runat="server" Text="AutoPostBack" AutoPostback="true" Height="20px" OnCheckedChanged="chkAutoPostback_CheckedChanged" ></asp:CheckBox> <br /> <br /> <asp:DropDownList runat="server" ID="lstTypes" AutoPostBack="true" OnSelectedIndexChanged="lstTypes_Changed"> <asp:ListItem Text="Red" Value="Red" ></asp:ListItem> <asp:ListItem Text="Green" Value="Green"></asp:ListItem> </asp:DropDownList> </form> </body> </html>
and the Codebehind:
namespace Test
{ public partial class Postback : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { } protected void btnSubmit_Click(object sender, EventArgs e) { Response.Write("button "); } protected void chkAutoPostback_CheckedChanged(object sender, EventArgs e) { Response.Write("checked "); } protected void lstTypes_Changed(object sender, EventArgs e) { Response.Write("selectionChanged "); } } }
This code basically spits out which events are fired. If you run this by:
- Loading the page
- Click the checkbox (you see checked event fired)
- Go back (no load - browser cache)
- Click the button
What you'll see is that when you click the button is that both the Checked event and the button submit code are fired. What's interesting is that when you click the BACK button the checkbox stays checked! So now you're firing a change event when in fact nothing has changed.
Apparently this is some sort of browser caching going on with the back button behavior. If I View Source of the generated page, the page has the __Eventxxx values empty. However, if I use a DOM viewer like FireBug it clearly shows that the __EVENTXXXX variables are populated. Here's the view after the Back button operation:
In most situations this is probably not a big issue, but in some situations where you're depending on certain events NOT firing when the shouldn't <s> this may cause issues. For example, in the code above the checked event fires before the button submit so if for whatever reason the value of the checked property adjusts other values before submitting that may effect what the submit behavior is expecting.
Not sure how to address this directly. I wouldn't say this is a bug in ASP.NET, and I'd be even hard pressed to call this a browser bug - browsers do write submitted POST values back into the variables of a page when you click the back button and that certainly has to work.
I suppose the solution is to be very defensive in your coding of change events by explicitly checking for the values of the changes and not just always 'just' executing code on the event. This can be harder than it sounds especially with list controls <s>...
In West Wind Web Connection - well, I have another issue in that unlike ASP.NET it only fires the __EVENTTARGET event and not the button submit at this time. This needs to change so it works as ASP.NET does so at least the submit behavior is fired in this situation. Currently the __doPostback behavior fires the event, but the button submit never fires which results in completely different results.
Tricky one to track down this one - hope this helps someone out in the future.
Other Posts you might also like
- Map Physical Paths with an HttpContext.MapPath() Extension Method in ASP.NET
- Adding minimal OWIN Identity Authentication to an Existing ASP.NET MVC Application
- Getting the Client IP Address in ASP.NET Core
- Adding Default Assemblies, Namespaces and Control Prefixes in Web.Config
- Resolving Paths To Server Relative Paths in .NET Code
The Voices of Reason
# re: __doPostBack and the Back Button
What FireFox debugger are you using in your screen shots ( I know I can sound like a n00b)
Peace
-Jon
# re: __doPostBack and the Back Button
# re: __doPostBack and the Back Button
"Invalid postback or callback argument. Event validation is enabled using <pages enableeventvalidation="true" /> in configuration or <%@ page enableeventvalidation="true" %> in a page. For security purposes, this feature verifies that arguments to postback or callback events originate from the server control that originally rendered them. If the data is valid and expected, use the ClientScriptManager.RegisterForEventValidation method in order to register the postback or callback data for validation."
As far as my research goes I've found out that this exception gets thrown if the post data is tampered with, since this is not the case, of course I could turn off event validation, but that's a quick n' dirty thing of which I am not fond.
This seems to be a random error - anyway I haven't been able to reproduce the behavior.
# re: __doPostBack and the Back Button
This means that the action is reset for each post back.
# re: __doPostBack and the Back Button
I am also facing some issues with Back Button of Internet Browser as well.
Actully Page Load event of my page is not firing when i click on Back Button of Internet.
Please suggest !!!!!!!!
Thanks in advance.
Regads,
Nitin kukreja
# re: __doPostBack and the Back Button
John
# re: __doPostBack and the Back Button
Is there any other workaround besides "be very defensive in your coding of change events"???
Is it possible to prevent the OnCheckedChanged event at the JavaScript level, before the postback occurs, by overriding (creating a custom checkbox-control) the OnCheckedChanged method??
Thank's in advance!!!
Robert Baminger
# re: __doPostBack and the Back Button
I'm trying to create a simple page that uses two drop down lists. The page is used to select report types on an intranet.
The first drop down sets a variable which corresponds to a sub-directory. The second drop down sets a variable which corresponds to either a weekly.aspx or monthly.aspx file. Additionally, as soon as the item is selected in dropdownlist2, the browser immediately opens up the page using the catonated variables.
However, I want the default.aspx page to reset the drop down lists if a user presses the back button.
The other requirements are that I need to keep this as simple as possible...which I've tried to do through some naming standards.
I'm using Visual Studio 2005, vb.Net 2.0
Can anyone tell where I'm going wrong?
ASPX:
<%@ Page Language="VB" AutoEventWireup="True" CodeFile="Default.aspx.vb" Inherits="_Default" %> <!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 runat="server"> <title>Report Graphs</title> </head> <body> <form id="form1" runat="server"> <div style="text-align: center"> <span style="font-size: 14pt; font-family: Arial">Report Graphs.<br /> </span><span style="font-size: 12pt"><span style="font-family: Arial">Select Month and Report Type</span><br /> <br /> <asp:DropDownList ID="DropDownList1" runat="server" EnableViewState="False" OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged" Width="100px"> <asp:ListItem Selected="True">Month</asp:ListItem> <asp:ListItem>Jan</asp:ListItem> <asp:ListItem>Mar</asp:ListItem> <asp:ListItem>Feb</asp:ListItem> </asp:DropDownList><br /> <asp:DropDownList ID="DropDownList2" runat="server" AutoPostBack="True" EnableViewState="False" OnSelectedIndexChanged="DropDownList2_SelectedIndexChanged" Width="100px"> <asp:ListItem Selected="True">Rpt Type</asp:ListItem> <asp:ListItem>Weekly</asp:ListItem> <asp:ListItem>Monthly</asp:ListItem> </asp:DropDownList></span></div> </form> </body> </html>
My default.aspx.vb:
Partial Class _Default Inherits System.Web.UI.Page Dim strFolder As String Dim strPage As String Dim strURL As String Sub page_load() If Page.IsPostBack Then Page.Response.Cache.SetCacheability(HttpCacheability.NoCache) Response.Expires = 0 Response.Cache.SetNoStore() Response.AppendHeader("Pragma", "no-cache") DropDownList1.SelectedIndex = 0 DropDownList2.SelectedIndex = 0 End If End Sub Protected Sub DropDownList1_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles DropDownList1.SelectedIndexChanged If DropDownList1.SelectedItem.Text = "Jan" Then strFolder = "./Jan/" ElseIf DropDownList1.SelectedItem.Text = "Feb" Then strFolder = "./Feb/" ElseIf DropDownList1.SelectedItem.Text = "Mar" Then strFolder = "./Mar/" Else strFolder = "" End If End Sub Protected Sub DropDownList2_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles DropDownList2.SelectedIndexChanged If DropDownList2.SelectedItem.Text = "Weekly" Then strPage = "Weekly.aspx" ElseIf DropDownList2.SelectedItem.Text = "Monthly" Then strPage = "Monthly.aspx" Else strPage = "" End If strURL = strFolder & strPage Response.Redirect(strURL) End Sub End Class
# re: __doPostBack and the Back Button
I created a client-side script that fires when you click the button (and before the browser processes __doPostBack). This script sets the value of a hidden field to 1. In the DropDownList control's serverside SelectedIndexChanged function, I check the value to make sure it ISN'T 1.
Obviously you have to set the value of the hidden field to 0 by default and AFTER each PostBack. It won't work if you set it to 0 in the Page_Load because that occurs before the PostBack -- you have to use the Page_PreRender event.
example.aspx javascript:
<script type="text/javascript"> var theForm = document.forms['form1']; if (!theForm) { theForm = document.form1; } function test() { theForm.SearchBtn_Clicked.value = '1'; } </script>
example.aspx controls:
<input id="SearchBtn_Clicked" type="hidden" value="0" runat="server"/> <asp:Button ID="ContactSearchBtn" runat="server" Text="Go" OnClick="ContactSearchBtn_Click" OnClientClick="SetHiddenField()" />
code-behind:
protected void Page_PreRender(object sender, EventArgs e) { SearchBtn_Clicked.Value = "0"; } protected void ContactDrpDwnLst_SelectedIndexChanged(object sender, EventArgs e) { if ( SearchBtn_Clicked.Value == "0" ) { string contactid = ((DropDownList)sender).SelectedValue; if ( contactid != "" ) { Response.Redirect("contactprofile.aspx?id=" + contactid); } } }
I'm sure there is a better way to do it, but this is what I came up with.
# re: __doPostBack and the Back Button
Please rename the javascript function from "test()" to "SetHiddenField()"
# re: __doPostBack and the Back Button
We a javascript function to the YUI's onContentReady event of the main ASP.NET form (which is fired on page load, back button or forward button). In that function we set theform.__EVENTTARGET = "" and theform.__EVENTARGUMENT = "" every time (replace 'theform' with you ASP.NET form variable here, generally 'form1').
No each page we load has just those two items reset, but all other form variables are fine.
# re: __doPostBack and the Back Button
sorry
# re: __doPostBack and the Back Button
Has anyone tried turning caching off for these pages?
# re: __doPostBack and the Back Button
# re: __doPostBack and the Back Button
The code is history.back() not window.back()
# Problem with the Back Button
I have an application made by using asp.net,C#.In that application there is a page having gridview displaying results.The grid view has a template column containing hyperlink. On click of the hyperlink there is modal popup opened using Javascript. The modal popup is closed successfully by closing it.Now I redirect to some other page for some operations. Now staying on the same page when I click the browser back button the modal popup is opened.The same scenario is observed in case the page is refreshed.I have opened the application using IE7 browser. Can you please help me to get solution for stopping the modalpopup to open.
What I found is on click of the browser back button the modal popup page is brought from the cache. The page_Load event is also not fired. Have you any solution for this problem then provide me.
Any help is appreciated in advance.
Thanks,
Santosh
# re: __doPostBack and the Back Button
I have Image button on my page which used for user registration,but after registring user when i press back button of browser, image button's click event again fires during page load.Please,tell me how to solve this?& why this is happening?
# re: __doPostBack and the Back Button
The browser's preservation of form data is actually a very good thing. Let's say you submit a post to a forum, but the web server craps out on you; it is very desirable to be able to hit the back button and re-submit the post later on. In addition, this form-data-preservation means that javascript state can be saved prior to navigation, and restored when back/forward functionality is used.
The ugly solution is to prevent any sort of caching of the page in question. This is not desirable in my book, as the above functionality is lost. A more elegant solution depends on exactly how event processing works. I am very interested in where you go with this, as I currently have an application that suffers mildly from this issue. I have a login control on the same page as my main content, which you can think of as a wiki. If the authentication cookie expires and I have just made major changes to an article, I want to be able to login and have the changes saved; many web applications simply cannot do this.