Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
West Wind WebSurge - Rest Client and Http Load Testing for Windows

__doPostBack and the Back Button


:P
On this page:

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.

Posted in AJAX  ASP.NET  Web Connection  

The Voices of Reason


 

Luke
May 23, 2007

# re: __doPostBack and the Back Button

I have experienced problems I think are similar to this. The problem seems to be how ASP.NET handles postback data, how it converts that to actual events. I fear the only solid option is to use the .NET Reflector to peer into the code and see exactly how things work.

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.

Jon
May 23, 2007

# re: __doPostBack and the Back Button

Hey Rick.

What FireFox debugger are you using in your screen shots ( I know I can sound like a n00b)

Peace
-Jon

Ted Jardine
May 23, 2007

# re: __doPostBack and the Back Button


Søren Jacob Lauritsen
May 23, 2007

# re: __doPostBack and the Back Button

Could the back-button be playing a role in another weird problem I have on one of my sites? From time to time I get an exception saying:

"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.


July 04, 2007

# 本周ASP.NET英文技术文章推荐[05/20 - 06/02] - Dflying Chen @ cnblogs - 博客园


ghnz
August 29, 2007

# re: __doPostBack and the Back Button

I have found a quick fix for this is to set the PostbackUrl on all buttons/links that use the default action to Request.RawUrl.

This means that the action is reset for each post back.

Nitin Kukreja
October 29, 2007

# re: __doPostBack and the Back Button

Hey,

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

John Bergman
November 15, 2007

# re: __doPostBack and the Back Button

Nitin, check the top of your aspx page, do you have AutoEventWireup="true"? If not, I suspect this could be the cause.

John

baroso
December 07, 2007

# re: __doPostBack and the Back Button

I'm currently developing an AJAX application and I'm also experiencing the problem of the OnCheckedChanged event occuring when I click on a LinkButton, with the exception that the BACK button of the browser is not involved!

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

Ted Wagner
December 27, 2007

# re: __doPostBack and the Back Button

I am having a similar issue and need.

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

William Ness
May 10, 2008

# re: __doPostBack and the Back Button

Here is my solution.

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.

William Ness
May 10, 2008

# re: __doPostBack and the Back Button

Slight error in my last post:

Please rename the javascript function from "test()" to "SetHiddenField()"

Layle Baker
May 30, 2008

# re: __doPostBack and the Back Button

I know this is digging up old stuff, but a solution we used on our ecommerce site (where with a weird hybrid of the ASP.NET page model and a new presentation model we are working on are mixed in together - we were getting this same *exact* issue) was to use the YUI javascript classes - specifically YAHOO.util.Event (and the method YAHOO.util.Event.onContentReady).

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.

Layle Baker
May 30, 2008

# re: __doPostBack and the Back Button

should be theform.__EVENTTARGET.value = "" and theform.__EVENTARGUMENT.value = ""


sorry

Christopher P. Kile
June 09, 2008

# re: __doPostBack and the Back Button

__EVENTTARGET et al. are all themselves hidden variables with ViewState enabled, which in turn enables their values to be saved through postbacks. As such, their values are POSTED values, and are restored just as reliably as the values of the checkboxes when the cached pages are accessed.

Has anyone tried turning caching off for these pages?

Jack Padova
June 17, 2008

# re: __doPostBack and the Back Button

Just add window.back() right after window.showModalDialog(....). This will remove the dialog from the history list.

Jack Padova
June 17, 2008

# re: __doPostBack and the Back Button

Correction to above:
The code is history.back() not window.back()

santosh kumar patro
December 08, 2009

# Problem with the Back Button

Hi Rick,

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

Amol
June 28, 2010

# re: __doPostBack and the Back Button

Hi,
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?

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024