Disable the Browser Back Button in your ASP.NET Application
If you’ve just come to accept the Back button as a necessary evil, I’ve
got a few simple solutions for you that prevent the user from backing up
past a designated “one-time only” page in your application.
Solution 1: Disable the Back button completely
This is the simplest solution that disables the Back button completely. How simple? Just add
onload=”window.history.forward();” to the <body> tag in the page(s) that you don’t want the user to be able to click Back to.
<body onload="window.history.forward();">
Solution 2: Disable caching for the page
OK, so let’s just not cache the page with the Finish button, the one
that does all the work that we don’t want repeated should the user click
Back and then resubmit. We can do that by overriding the OnPreInit
method (same thing as, but more efficient than, handling the PreInit
event) and setting the various caching-related properties on the
Response object to prevent the browser from caching the page:
| protected override void OnPreInit(EventArgs e) |
| Response.ExpiresAbsolute = DateTime.Now.AddDays(-1d); |
| Response.Expires = -1500; |
| Response.CacheControl = "no-cache"; |
| Response.Cache.SetCacheability(HttpCacheability.NoCache); |
Solution 3: Use this “hidden field/script/postback” trick
This solution is a little more involved, but is more flexible and
opens up other interesting possibilities (for example, it gives you
greater control when server-side validation is involved).
The gist of it? — You can’t directly disable or otherwise control the behavior of the Back button. But you can
deliver a page that always forces a redirect, which gets stored
normally in the browser’s history, such that when the user clicks Back,
the redirect will always be forced.
Here’s the recipe:
1) Add a hidden field
In the .aspx markup, add a hidden field server control to your page that starts off with no initial value:
1 | <input type="hidden" id="hidIsCommitted" runat="server" /> |
This field will get set only when the code-behind performs the
processing you don’t want repeated (e.g., database save, credit card
charge) if the user clicks Back and then resubmits.
2) Just beneath the hidden field, add the following script:
1 | <script language="javascript" type="text/javascript"> |
2 | if (document.getElementById('<%= this.hidIsCommitted.ClientID %>').value == '1') |
4 | location.href = 'ThankYouPage.aspx'; |
This simple code tests the value of the hidden field, and if it is
set, the code redirects the user to the Thank You page (the page the
user is normally redirected to after clicking Finish). Of course, the
hidden field is not initially set, since we added it above with no value
and no code has set its value yet.
Note the importance of using both
document.getElementById and the bee-sting <%= %> server-side
replacement markup for the hidden field’s ClientID value. Using
getElementById ensures cross-browser compatibility, and the ClientID
property resolves to the actual ID generated for the hidden field in the
DOM, which includes additional unique identifiers if the element is
contained inside a templated control, content placeholder, or other
naming container.
3) Just beneath the script, add the following server-side span element with another script block inside of it:
1 | <span id="spnCommitScript" runat<span style="color:#000000;">="server" visible="false"> |
2 | <script language="javascript" type="text/javascript"></span> |
3 | document.getElementById('<%= this.hidIsCommitted.ClientID %>').value = '1'; |
4 | var theForm = document.forms['form1']; |
5 | if (!theForm) theForm = document.form1; |
This code sets the hidden field value and then performs a postback,
but because the script block is wrapped inside of a server-side span
element named spnCommitScript whose visible property is set to false,
this code is not actually sent to the client. Only when the span element
is made visible by server-side code will this client script get sent to
the client, and the server-side code will not make the span visible
until after completing the processing that occurs when the user clicks
Finish.
4) In the code-behind, just at the point in time when you have
completed processing (saving to the database, charging the credit card,
etc.), make the span visible. Basically, this is the same point in time
that you would normally issue a Response.Redirect to the Thank You page.
But instead, you just make the span visible:
01 | protected void btnFinish_Click(object sender, EventArgs e) |
03 | if (!this.PerformAdditionalValidation()) |
05 | this.lblValidationErrorMessage.Visible = true; |
09 | // Update database, charge credit card, etc. |
10 | <span style="color:#993366;"><span style="color:#000000;">this.spnCommitScript.Visible = true;</span> |
The result? When the page returns to the client, the hidden field
value is still not set. So the initial JavaScript test still returns
false and the user does not get redirected to the Thank You page yet.
But right after that, additional JavaScript code executes that has never
execute before because the span has always been invisible. And that
JavaScript code goes ahead and sets the hidden field, and then invokes a
postback. The page returned to the client after the postback is then
stored in the browser’s history cache normally. But this version of the
page has the hidden field value set which causes redirect to the Thank
You page. So clicking Back from the Thank You page results in reloading a
page that forces itself to redirect immedately back again to the Thank
You page. If the user clicks the Back button all day long, they won’t be
able to back up past the Thank You page. Even if they advance several
pages forward in the application, they’ll be able to click Back only up
until reaching the Thank You page, but no further back than that.
All of the markup in steps 1, 2, and 3 can be placed
in a Master page, so that it can be shared by all Content pages. With
this approach, you would implement the redirect page as a variable
rather than hard-coded as ThankYouPage.aspx and thus achieve an
extremely lightweight framework for handling the Back button in this
manner across your entire application. Only the code in step 4 (modified
to also set the desired redirect page name) needs to be applied
whereever you’d normally code an ordinary Response.Redirect in your
code-behind.
Hope this information saves you some grief trying to cope with the Evil Back Button!
No comments:
Post a Comment