Click here to Skip to main content
Email Password   helpLost your password?

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.

<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:

    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.

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.

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralAvoid Duplicate record insertion on page refresh in ASP.NET
elizas
2:21 15 Feb '10  
One of most common issue which many of the web developers face in their web applications, is that the duplicate records are inserted to the Database on page refresh. If the web page contains some text box and a button to submit the textbox data to the database. In that case when the user insert some data to the textbox and click on the submit button, it will save the record to the Database and then if the user refresh the web page immediately then the same record is again saved to the database as there is no unique keys that can be used to verify the existence of the data, so as to prevent the multiple insertion.

http://www.mindfiresolutions.com/Avoid-Duplicate-record-insertion-on-page-refresh-in-ASPNET-486.php[^]
Cheers,
Eliza

GeneralMy vote of 1
Judgemewnt Day
23:28 26 Oct '09  
language is more complicated
GeneralI have another easy approach that works for me
bitsbuilt
12:56 1 Apr '09  
I am doing this using a single session variable...

I have a session variable set to false on page load as

protected void Page_Load(object sender, EventArgs e)
{
if(!IsPostBack)
Session["issubmitted"] = "false";
}

Now on button click
protected void btnNextData2_Click(object sender, EventArgs e)
{
//check if the session variable is false so that u have to do this
for the first time
if (Session["issubmitted"].ToString() == "false")
{
//then here i write the data to the data base
}
//then after the data is written to the database i set the session to true

Session["issubmitted"] = "true";

}
}
thats all it works... Shucks
GeneralRe: I have another easy approach that works for me
Jeremy Schell
13:25 1 Apr '09  
Yes, this is another way which will work....however in an environment where the web site is either load balanced across multiple servers or, more importantly, when the Application Pool uses more than one Worker Processes then session information may not persist. When the sessions are handled in SQL it becomes a little more reliable however we've had situations where worker processes in the same application pool have trouble accessing common session information from SQL.
QuestionSQLEXPRESS
Blestemat1
10:16 28 Apr '07  
Thank you for providing this. I've looking for a solution to this.

Can I use it with SQLEXPRESS and integrated security?

How do I set up the keys in web.config?

Thanks
QuestionColude you provide source code ?
rainmaker HO
20:38 18 Sep '05  
Sir:
Colude you provide source code ? thanks.
GeneralDoesn't Work,,,
fitnessworkout
13:23 17 Aug '05  
I placed all the information as decribed on your page including the following in my web.config file



I also placed the the following in my code:

Dim validator As New TectonicConcepts.FormValidator.FormValidator
If validator.ValidatePostback = True Then
End If

It doesn't seem to work... the first time I hit my button the above code is too execute nothing happens.
The code skip everything in between the if then end statement.

The FormManager database was correctly installed on my server.
It also doesn't seem it's writing anything to the database.
I must be doing something wrong.
GeneralRe: Doesn't Work,,,
Jeremy Schell
13:32 17 Aug '05  
Definitely sounds like you have something wrong. Make sure you have placed the server control onto your page within the HTML FORM tags and within a visible panel. Second, make sure your connection string is set properly.
Generaleasier way
eyoung70
16:42 4 Aug '05  
I believe the easiest way to accomplish this is to just add something to the querystring after the first successful load (like 'Refreshed=1') and then response.redirect the page back onto itself. Then, in the page_load, if querystring['Refreshed'] == '1', avoid database writes, etc.
General[Message Deleted]
Durlabh Jain
23:54 4 Aug '05  

GeneralRe: easier way
Jeremy Schell
5:15 5 Aug '05  
As mentioned in Terri Morton's article there are a number of ways to accomplish this funcitonality such as querystring parameters Refresh=1 and session("newForm").

however

Refresh = 1 can cause problems in multi-step forms and is quite easy to hack if you are trying to prevent automated submissions.

Also, session and cookie variables can be used but often we work with contracts where part of the specifications state that session variables can not be used so an alternative has to be engauged. Also, from a workflow scenario if you use sessions on a multi-step form you must remember to track the session and reset it on each step of the multiple step form and track what the next expected value should be.

We've found with this scenario that it works regardless of the specifications and when the server control is placed at the bottom of a web form we can just validate it on each postback without having to track what the next session variable name or value should be.

Take a moment to read Terri's article referenced in my article as it very clearly addresses many of these methods.
GeneralRe: easier way
Sean Rock
23:31 27 Aug '05  
this is exactly how i do it Durlabh.
GeneralRe: easier way
Stevercakes
14:28 25 Jan '06  
Thanks for this! Works like a charm!!
GeneralRe: easier way
DariePOP
7:02 28 May '06  
<script runat="server"> Sub page_prerender()
If Page.IsPostBack Then
Response.Redirect("default.aspx")
End If

End Sub
</script>


Laugh
GeneralRe: easier way
Jeremy Schell
7:30 28 May '06  
Unfortunately in this case the form will never post. Each time the person tries to post, even the first time, it will redirect and you'll never collect the necessary data. I guess if your intend is to never collect form data this method would be the best.

GeneralRe: easier way
DariePOP
7:33 28 May '06  
re re Smile

the script i've posted is up and running.
i've needed-it for a shout-box.

works fine Smile

Poke tongue


Last Updated 25 Aug 2005 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010