Preventing Duplicate Inserts on Browser Refresh (F5)

It is working now!  This is right from the battle ground to you.  The problem:  you have an insert button that inserts a record into a database.  If user presses refresh (F5) button immediately after inserting a new record, more and more new records continue to be written into the database.  Usually this problem can be resolved by using Response.Redirect(), but not always.

In my case, I can’t call Response.Redirect() because I will loose all of the page current state information, and I do not want to create more problems by saving and restoring all this information on each page load.

So, if you can’t use Response.Redirect() method, you can use this method instead. This method consists of two steps:
(01) Mark a hidden filed just before leaving the page, right after pressing Insert button, and
(02) Compare the value just before calling an insert procedure on server side.

Here is the under-the-hood look into details.  When user actually presses the Insert button, a one line script is changing a value of a TextBox somewhere on the page.  Refresh (F5) button does everything exactly the same with the exception of this value change.  And that is how can we distinguish is it an Insert or a Refresh.

Inside your ASPX page you need to add two controls and add OnClientClick call that updates one of these controls.  The usual trick here is to use local <SPAN> tag to store long client ID of a server TextBox control.

<FooterTemplate>
    <asp:LinkButton ID="btnInsert" runat="server"
        CausesValidation="True" CommandName="Insert"
        OnClientClick='document.getElementById(spanTimeStamp.innerHTML).value = new Date;'
        Text="Insert" ValidationGroup="ExpenseInsert" ToolTip="Add a New Record" >
    </asp:LinkButton>
</FooterTemplate>
. . . . . .
</asp:GridView>
. . . . . .
<span id="spanTimeStamp" style="display: none;"><%= txtTimeStamp.ClientID %></span>
<asp:TextBox ID="txtTimeStamp" runat="server"  style="display: none;"></asp:TextBox>

Also note that you can’t use Display=”false”, because it will make controls non-existent on the client side and OnClientClick will not work.  That is why we had to use style=”display: none;”

Inside your code-behind file you need to add one more IF statement:

 protected void gvExpenses_RowCommand(object sender, GridViewCommandEventArgs e)
{
    switch (e.CommandName)
    {
        case "Insert":
            TextBox _txt = (TextBox)this.FindControl("txtTimeStamp");
            // Distinguish between actual Insert and simple F5/Refresh
            if (_txt.Text != (string)Session["InsertTimeStamp"])
            {
                int newID = Proccess_Insert_Request();
            }
            Session["InsertTimeStamp"] = _txt.Text;
            gvExpenses.DataBind();
            break;
    }
}

That is it. Now, when user presses Insert button (inside GridView in this example), Proccess_Insert_Request() is executed.  When user presses Refresh button (F5), call is omitted.  Perfect!

(Visited 1,120 times, 1 visits today)

3 Comments

  1. Thanks to previous contributor – “rg”.

    However, I am confused. I’ve tried suggested solution, and it only worked in Firefox for a short while.

    Then I went back to my script, and now my solution works both in IE and Firefox.

    I will try to find an explanation and to post a solution that works both for IE and Firefox.

  2. Change
    OnClientClick=’document.getElementById(spanTimeStamp.innerHTML).value = new Date;’
    to
    OnClientClick=”document.getElementById(document.getElementById(‘spanTimeStamp’).textContent).value = new Date;”

    Then it well

    Thanks

  3. The trick mentioned in the post is simple and easy to understand.
    I tweaked the trick to use Hidden value field instead of span and textbox.
    Anyways thanks for the post i was searching for a simple solution since few days.

Your question, correction or clarification Ваш вопрос, поправка или уточнение