I was tasked to figure out why we had duplicate records in our datafeed and it turns out we actually had duplicate data. With AJAX and partial page rendering users don't have all the telltales that something is happening even with an UpdateProgress control and animated gif. Our users were getting impatient and clicking the submit button multiple times.
The simple version to prevent multiple submits is to disable the submit button after the first click:
protected override void OnInit(EventArgs e)
{
this.Button1.Attributes.Add("onclick", "this.disabled = true;");
base.OnInit(e);
}
This isn't quite enough though. The browser will ignore a submit button that has been disabled so the postback will occur but the Event Handler won't fire since ASP.Net doesn't know what button submitted the request. To fix this we just set the UseSubmitBehavior to false.
<asp:Button ID="Button1" runat="server" Text="Button" onclick="Button1_Click" UseSubmitBehavior="false" />
This method will work fine unless you have any validators on your page. Then we have to get into using the Page_ClientValidate function that will fire our validators. So our onclick attribute looks like this:
protected override void OnInit(EventArgs e)
{
this.Button1.Attributes.Add("onclick", "if (typeof(Page_ClientValidate) != 'function' || Page_ClientValidate()) { this.disabled=true; " + Page.ClientScript.GetPostBackEventReference(this.Button1, "").ToString() + "}");
base.OnInit(e);
}
The Page.ClientScript.GetPostBackEventReference allows us to fire a postback from a client event (http://msdn.microsoft.com/en-us/library/system.web.ui.clientscriptmanager.getpostbackeventreference.aspx)
Lastly, what if we have validation groups on the page? The Page_ClientValidate function takes optional parameters to allow us to specify the validation group so our final block looks like this:
protected override void OnInit(EventArgs e)
{
this.Button1.Attributes.Add("onclick", "if (typeof(Page_ClientValidate) != 'function' || Page_ClientValidate('ValidationGroup1')) { this.disabled=true; " + Page.ClientScript.GetPostBackEventReference(this.Button1, "").ToString() + "}");
base.OnInit(e);
}