Click here to Skip to main content
15,563,248 members
Articles / Web Development / ASP.NET
Article
Posted 4 Aug 2005

Stats

101.5K views
520 downloads
45 bookmarked

Preventing Duplicate Record Insertion or Page Refresh on postback of a Web Form

Rate me:
Please Sign up or sign in to vote.
3.40/5 (9 votes)
25 Aug 2005CPOL5 min read
A browser, cookie, session independant method to prevent multiple postbacks and page refreshes when processing web forms.

Introduction

As with many Internet developers one of the biggest challenges and end user frustrations is the resubmission of data or refresh of a form to post information to a database by an unaware user. Quite often this happens and the user for whatever reason will resubmit or refresh the form and potentially cause chaos with database and/or email submissions. There have been a number of theories presented on this subject, one of the most thorough I’ve read being from Terri Morton. It is not my intent to dispute which of these methods is best but instead to offer an alternative suggestion.

History

Several years ago I was challenged by a company which was performing online contest submissions to limit users to one submission per "typed" entry. Additionally they wanted to prevent mass submission companies from flooding their contest with un-prospected candidates and automated entries. After looking at many options, I concluded to create a single use formKey that I could assign and track at the server level for each user every time a form was loaded. Once the form was submitted, I would confirm the existence of the formKey for that form and allow the submission to be processed. At that point, the key would be purged from the system and could no longer be used. Then if the user hits refresh or tries to repost the submission, I could handle the repost in any manner knowing it was a repeat submission. In the cases when a developer is using a multi-step form on a single web form, this process can easily be integrated to maintain each “step” of the form submission process. To expand upon our solution, we’ve integrated it into a VS.NET toolbox server control that can easily be dragged onto a web form and then attached from the code-behind to authenticate the Postback as a single submission making it easy for any developer to integrate.

The process

The overall process works as follows:

  1. Initial page load – Register the web form and generate a unique formKey, e.g. "A".
  2. Once the page is completed and a postback is done, formKey "A" exists within the POST form collection. We authenticate this formKey against the database for the web form to confirm it is validated. Once confirmed, the page processing is allowed to continue and the formKey is deleted. If the user presses Refresh within the browser or their Back button and reposts the data, formKey "A" will again be contained within the POST form collection and will no longer authenticate within the database.
  3. Simultaneously a new formKey "B" is generated for the next possible postback and formKey "A" will no longer function. This is necessary for multiple step forms, and upon postback, formKey "B" can be properly authenticated.
  4. This process repeats itself each time the screen is refreshed or a postback is initiated.

Because this solution required the use of a database, we also wanted the solution to be scalable to all of our clients and their forms so we updated the database and server control to allow a single control to manage multiple sites and multiple forms on each site. As each site and form is called, the server control registers the web site and web form within the database for future use and tracking.

Implementation

All formKeys are created by the server control and then registered with the database for use on each user requested form. The database consists of three tables: Sites, Forms and FormKeys. Each record within the Sites table maintains a unique hostname where forms are submitted from. Similarly, the Forms table maintains each URL where a form is submitted from. Finally, the FormKeys table tracks each formKey provided by the server control, user’s IP address, and the specific Site and Form in which the key is valid. This is all passed through the stored procedure "spInsertFormKeymKey" when the form is originally requested. Currently the FormValidator maintains keys for one day but the system can easily be configured from the stored procedure "spAuthenticateFormKey" to enforce a shorter life cycle for each key.

Upon each postback the developer calls the ValidatePostback function which provides a Boolean response (True/False) of whether the formKey provided on the form was valid or not for the current submission location. If False, either the form is a repeat submission or it was an automated submission from some other source. When the ValidatePostback function is called, the server control calls the "spAuthenticateFormKey" procedure providing the user’s IP, formKey as found in the POST/GET collection, hostname and file name of the form. This is compared against previous submissions. If one matches, a successful response is sent to the server control and the previous formKey removed from the database.

Usage of the server control is extremely simple, add the server control to your VS.NET or WebMatrix toolbox and drag the control onto your web form. For best implementation, place it between the FORM tags but outside any possible hidden panels, tables or other components that may change throughout the lifecycle of your form. Next, add the following four keys to your web.config with the appropriate connection string information to your database.

XML
<add key="FV_dsn_Server" value="[SERVER NAME OR IP]"/>
<add key="FV_dsn_Database" value="FormManager"/>
<add key="FV_dsn_Username" 
      value="[USERNAME TO CONNECT TO SQL SERVER]"/>
<add key="FV_dsn_Password" 
      value="[PASSWORD TO CONNECT TO SQL SERVER]"/>

You can also add the following key FV_EnforceValidation to the web.config and set it to False to disable all form validation on a site for your testing purposes so that you can submit/resubmit without having to register a formKey. Be sure to either remove this key or set to True once you are done testing or it will not protect against duplicate submissions.

When you do a postback just wrap your actual processing within the following code:

VB
Dim validator As New TectonicConcepts.FormValidator.FormValidator

If validator.ValidatePostback = True Then

    ' DO SOMETHING WITH IT HERE

EndIf

If you have a redirect or thank you display message or processing to a next screen, you’ll want to place that outside this code block. For example on our contact form, we do the following: on the first postback we send an email but on subsequent refresh of invalid postbacks we don’t send an email but still display the Thank you panel.

VB
Private Sub subForm_Click(ByVal sender As System.Object, _
          ByVal e As System.EventArgs) Handles subForm.Click
    If Page.IsValid Then
        Dim validator As New _
                TectonicConcepts.FormValidator.FormValidator
        If validator.ValidatePostback = True Then
            Dim mail As New _
              TectonicConcepts.TemplateMailer.SendTemplateEmail
            mail.SendTemplateMail(_
                "Response from the Tectonic Concepts Website", _
                "MailTemplates/ContactUsForm.txt", "", _
                CMS.Settings.ContactFormSender, _
                CMS.Settings.ContactFormRecipient, _
                CMS.Settings.ContactFormBccRecipient, _
                True, True, True, False, Me.Controls)
        End If
        ContactForm.Visible = False
        Contactus_Intro.Visible = False
        ContactUs_ThankYou.Visible = True
    EndIf
End Sub

The database setup script and FormValidator server control can be downloaded here.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
Besides being a husband and father, I am the Director of Interactive Media for PriceWeber, a full-service branding agency headquartered in Louisville, KY. I have extensive experience in digital (1.0 and 2.0) development as well as strategic design of user experience and influence campaigns. Since 1994, I’ve designed and/or developed interactive promotions, CRM/Loyalty programs, email/SMS marketing campaigns, mobile marketing/mobile apps, social media strategies, SEO/SEM and web sites/applications for hundreds of companies, associations and organizations throughout all fifty states, Canada, Mexico and Australia including; Microsoft, Brown-Forman, R.J. Reynolds, U.S. Air Force, U.S. Air National Guard, U.S. Department of Defense, Kentucky National Guard, Anheuser-Busch, The Walt Disney Company, Wall Street Journal Online, Valvoline, Valvoline Instant Oil Change, ArvinMeritor, Cummins, Inc, Barnes-Jewish Hospital, Community Health Systems, Humana, Purina Mills, Lexmark, General Electric, U.S. Smokeless Tobacco, National City Bank, Star Bank, Fifth Third Bank, Hilliard Lyons, Makers Mark, the Kentucky Lottery, the D.C. Lottery, Louisville Slugger, Morton’s The Steakhouse, Eli’s Cheesecake, Eli’s The Place for Steak and many others.

Comments and Discussions

 
GeneralAvoid Duplicate record insertion on page refresh in ASP.NET Pin
elizas15-Feb-10 2:21
elizas15-Feb-10 2:21 
GeneralMy vote of 1 Pin
Judgemewnt Day26-Oct-09 23:28
Judgemewnt Day26-Oct-09 23:28 
GeneralI have another easy approach that works for me Pin
bitsbuilt1-Apr-09 12:56
bitsbuilt1-Apr-09 12:56 
GeneralRe: I have another easy approach that works for me Pin
Jeremy Schell1-Apr-09 13:25
Jeremy Schell1-Apr-09 13:25 
QuestionSQLEXPRESS Pin
Blestemat128-Apr-07 10:16
Blestemat128-Apr-07 10:16 
QuestionColude you provide source code ? Pin
Member 34159518-Sep-05 20:38
Member 34159518-Sep-05 20:38 
GeneralDoesn't Work,,, Pin
fitnessworkout17-Aug-05 13:23
fitnessworkout17-Aug-05 13:23 
GeneralRe: Doesn't Work,,, Pin
Jeremy Schell17-Aug-05 13:32
Jeremy Schell17-Aug-05 13:32 
Generaleasier way Pin
eyoung704-Aug-05 16:42
eyoung704-Aug-05 16:42 
General[Message Deleted] Pin
Durlabh Jain4-Aug-05 23:54
Durlabh Jain4-Aug-05 23:54 
GeneralRe: easier way Pin
Jeremy Schell5-Aug-05 5:15
Jeremy Schell5-Aug-05 5:15 
GeneralRe: easier way Pin
Sean Rock27-Aug-05 23:31
Sean Rock27-Aug-05 23:31 
GeneralRe: easier way Pin
Stevercakes25-Jan-06 14:28
Stevercakes25-Jan-06 14:28 
GeneralRe: easier way Pin
DariePOP28-May-06 7:02
DariePOP28-May-06 7:02 
GeneralRe: easier way Pin
Jeremy Schell28-May-06 7:30
Jeremy Schell28-May-06 7:30 
GeneralRe: easier way Pin
DariePOP28-May-06 7:33
DariePOP28-May-06 7:33 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.