For years, most ASP.NET developers have been coming across the scenario where hitting the browser's refresh button or pressing the F5 key performs exactly the same steps last performed by their .NET code. To be short and simple, let's create a scenario where I have an ASP.NET application that has a form called Add Customer. This form has a button on it and when the user clicks that button, a customer is added to the file. If the user again hits the Add Customer button, another customer is added to the file. However, if the user presses a refresh button or hits F5 key at this point, exactly the same scenario will be repeated and one more customer is added, as well. Hence in ASP.NET whenever you hit F5, .NET repeats its last action. This happens even when the F5 event is not a genuine post-back event. Needless to say, developers want to get rid of this.
The same problem was faced by my colleague a few days back. We tried a lot searching on the Internet, where we found a few solutions, but those were either just the pseudo-code -- i.e. not properly working -- or something like a hit-and-trial. A few of them jumped straight across the head. Unfortunately, there was not a single solution that could be easily implemented in ASP.NET and justify itself.
After two days of searching on the Internet, I came up with just a little clue, although I don't remember the reference. It suggested that we could distinguish between a genuine post-back request and the one generated by browser's refresh. All server-side events that get fired on the post-back get fired on refresh also, but fortunately there exists one event,
onsubmit, that only gets fired when there is a genuine post-back request. It is the client-side event of the form placed on your web page.
Using the code
The logic of the following code is to have a hidden control on your web form and every time there is a genuine post-back request, the client script just appends one character to the existing value of that hidden control. At the server side, I take a shared variable that will retain its value through the application's life, i.e. it won't be written off on every page load.
The first time the
page_load event is executed, I assign that shared variable the value of
1. As I've stated, the main task is to distinguish between the genuine post-back request and the refresh one on the Add Customer button. The simple logic is that if it is the first time the event has been executed, then my shared variable will be
1. If it is not the first time, then the character length of the hidden control will be one more than its previous length. I can easily obtain the new length of the control from
Then every time a customer is added, I assign the current control length to that shared variable. Hence, the next time a customer is added, your length should be one more than that of the last time. At every genuine post-back request, a value is appended to the current value of the hidden control in the client-side script, called upon at the
onsubmit event of the form.
document.getElementById("Flag").value + 'P';
Partial Class _Default Inherits System.Web.UI.Page
Shared done As String
Protected Sub Page_Load(ByVal sender As Object,
ByVal e As System.EventArgs) Handles Me.Load
If Not Page.IsPostBack Then done = 1
Protected Sub AddCustomer_Click(ByVal sender As Object,
ByVal e As System.EventArgs) Handles AddCustomer.Click
If Len(Flag.Value) > Len(done) Or done = "1" Then
done = Flag.Value Else
Points of interest
This solution is appealing in that it is NOT asking you to play with complex things like HTTP headers, HTTP modules, setting sessions from the client, keeping unwanted checks on the code and database level, etc. It can also be applied to any scenario and in any version of ASP.NET where users are facing similar problems. Its solution is very simple and can be understood and applied even by a developer who has just started working with the technology.
- 27 June, 2007 -- Original version posted