ASP.NET怎么防止重复提交!!
如何防止用户连续点击多下BUTTON后将数据插入到数据库中
[解决办法]
public class RefreshServe : System.Web.UI.Page { private static ILog log = LogManager.GetLogger(typeof(RefreshServe)); private readonly string REFRESH_TICKET_NAME = "__RefreshTicketArray"; private readonly string HIDDEN_FIELD_NAME = "__RefreshHiddenField"; private readonly string HIDDEN_PAGE_GUID = "__RefreshPageGuid"; /// <summary> /// 为True表示页面刷新,False为正常提交 /// </summary> public bool IsPageRefreshed { get { if (IsPostBack && !CheckRefreshFlag()) { log.Debug("刷新了页面"); return true; } else { log.Debug("正常提交"); return false; } } } /// <summary> /// 呈现前更新标识 /// </summary> /// <param name="e"></param> protected override void OnPreRender(EventArgs e) { log.Debug("执行OnPreRender"); base.OnPreRender(e); UpdateRefreshFlag(); } /// <summary> /// 更新标识,正常提交都删除该次提交的时间,并生产当前新的时间 /// </summary> private void UpdateRefreshFlag() { #region Cookie模式 //注册页面唯一标识并返回 string pageGuid = SetCurPageGuid(); HttpCookie cookie = GetRefreshTicket(); if (cookie.Values.Count > 0) { cookie.Values.Remove(pageGuid); log.Debug("当前清除的cookie变是:" + pageGuid); } string submitTime = DateTime.Now.ToString("hhmmss.fffff"); //当前提交时间保存到隐藏域 ClientScript.RegisterHiddenField(HIDDEN_FIELD_NAME, submitTime); log.Debug("即将要新增的时间:submitTime:" + submitTime + " Guid:" + pageGuid.ToString()); cookie.Values.Add(pageGuid, submitTime); log.Debug("UpdateRefreshFlag中当前Cookie中存在的记录数为:" + cookie.Values.Count); for (int i = 0; i < cookie.Values.Count; i++) log.Info("cookie[" + cookie.Values.GetKey(i) + "]:" + cookie.Values[i]); Response.AppendCookie(cookie); #endregion } /// <summary> /// 验证是否刷新 /// </summary> /// <returns></returns> private bool CheckRefreshFlag() { HttpCookie cookie = GetRefreshTicket(); string pageGuid = GetCurPageGuid(); if (cookie.Values.Count > 0) { bool flag; if (cookie.Values[pageGuid] != null) flag = cookie.Values[pageGuid].IndexOf(GetCurSubmitTime()) > -1; else flag = true;//防止出现异常,总是可以提交 if (flag) log.Debug("提交时间存在,可以提交"); else log.Debug("无效的提交时间"); return flag; } return true; } /// <summary> /// 得到已保存的提交时间,没有新建,有返回 /// </summary> /// <returns></returns> private HttpCookie GetRefreshTicket() { #region Cookie模式,返回值为Cookie HttpCookie cookie; if (Request.Cookies[REFRESH_TICKET_NAME] == null) { cookie = new HttpCookie(REFRESH_TICKET_NAME); Response.AppendCookie(cookie); log.Debug("Cookie不存在,初始化"); } else { cookie = Request.Cookies[REFRESH_TICKET_NAME]; log.Debug("读取已存在的Cookie,当前Cookie中存在的记录数为:" + cookie.Values.Count + "具体有如下几条:"); for (int i = 0; i < cookie.Values.Count; i++) log.Info("cookie[" + cookie.Values.GetKey(i) + "]:" + cookie.Values[i]); } return cookie; #endregion } /// <summary> /// 获取当前提交时间 /// </summary> /// <returns></returns> private string GetCurSubmitTime() { string submitTime = Request.Params[HIDDEN_FIELD_NAME] == null ? "" : Request.Params[HIDDEN_FIELD_NAME].ToString(); log.Debug("执行GetCurSubmitTime:submitTime为:" + submitTime); return submitTime; } /// <summary> /// 设置页面唯一标识,通过Guid标识来区分每个页面自己的提交时间 /// </summary> private string SetCurPageGuid() { string guid; if (!IsPostBack) { if (Request.Params[HIDDEN_PAGE_GUID] == null) { guid = System.Guid.NewGuid().ToString(); log.Debug("SetCurPageGuid注册了一个新的标识:" + guid); } else guid = GetCurPageGuid(); } else { guid = GetCurPageGuid(); } ClientScript.RegisterHiddenField(HIDDEN_PAGE_GUID, guid); return guid; } /// <summary> /// 得到当前页面的唯一标识 /// </summary> /// <returns></returns> private string GetCurPageGuid() { string pageGuid = Request.Params[HIDDEN_PAGE_GUID] == null ? "none" : Request.Params[HIDDEN_PAGE_GUID].ToString(); log.Debug("执行GetCurPageGuid()后Page_GUID为:" + pageGuid); return pageGuid; }需要刷新判断功能时新页面只需继承该类就可,通过引用属性IsPageRefreshed识别"为真表示刷新,假则是正常提交",将数据库的操作写在if(!IsPageRefreshed){ 数据库操作}即可,如果是刷新不会执行,代码中注释部分使用的是Session方式保存票证,因为session比较容易丢失且占内存,所以使用cookie,
[解决办法]
if your Button control doesn't need to set OnClientClick property, you can just do this:
<asp:Button ID="SearchButton" runat="server" Text="查詢" OnClientClick="this.disabled=true;this.form.submit();" UseSubmitBehavior="false" />
else if your Button Control need to set OnClientClick property:
OnClientClick="return confirm('您確定要修改嗎?');"
you should use JavaScript or jQuery to avoid dummy users' double clicking, like this:
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>未命名頁面</title>
<%-- 以下可用
<style type="text/css">
.disable
{
border-style:none;
border-width: thin;
background-color:Transparent;
color: #CCCCCC;
cursor:wait;
}
</style>
<script type="text/javascript" language="javascript">
function DisableButton()
{
document.getElementById("Button1").className = "disable";
document.getElementById("Button1").value = '正在提交.';
document.getElementById("Button1").onclick=Function("return false;");
return true;
}
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Button ID="Button1" runat="server" Text="Button(JS,CSS)" />
</form>
</body>
</html>
xx.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
Button1.Attributes.Add("onclick", "return DisableButton();");
}
}
}
[解决办法]
防止表单重复提交的实现方法!
我们做添加信息页面的时候经常会遇到这样的问题,用户有时候会重复的点击提交按钮(实际上测试人员经常这样干),会导致多次提交,产生重复数据,我们总是要写一段代码要在表单提交后把提交按钮设置disibled=true,这样的代码写了好几处。
初步想法是通过attachEvent在form的onsubmit事件中挂一个方法,每次触发该事件的时候都调用我们定义的方法,我们可以给form增加一个submited属性,每次判断这个属性,为false的时候继续提交表单并且设置form.submited=true,反之说明表单已经提交,就不再表单。
接下来,遇到了一些麻烦:
提交表单有三种方式(我目前用过的,就这三种)
<form action=test.aspx onsubmit="return false;" name=form1>
1.<input type=submit >submit按钮
2.<input type=text>当form中只有一个文本本框按回车的时候
3.<input type=button onclick=javascript:form1.submit()>自己写脚本提交
</form>
前两种是可以触发 onsubmit事件的,但是第三种不会。
显然,仅仅捕获onsubmit事件时不行的,还必须在form的submit方法执行前,判断表单是否在提交。
看看下面的代码,我们就明白了。
//修改当前页面所有表单的提交事件
function $setFormCheckSubmited()
{
var frms=document.forms;
for(var i=0;i<document.forms.length;i++)
{
frms[i].baseSubmit = frms[i].submit;//保存表单原来的submit 方法
frms[i].submited = false;//添加一个submited属性,并且设置其为false
frms[i].submit = new Function("$submitForm(this)");//
$addElementEventHandler(frms[i],"onsubmit","$submitForm(document.forms["+i+"])");
}
}
//提交一个表单,如果当前表单已经提交,按么就不会继续提交该表单
function $submitForm(frm)
{
if (frm.submited) return false;
frm.submited=true;
frm.baseSubmit();
}
//下面是addElementEventHandler的实现
/*
添加一个方法到到一个对象的一个的一个事件中
element 要设置的对象
eventName 事件名称, 字符串类型的。
methodName表示函数名称,字符串类型的。
*/
function $addElementEventHandler(element,eventName,methodName)
{
if (document.all)
{
element.attachEvent(eventName,new Function(methodName));
}
else
{
if (eventName.substring(0,2)=="on") eventName=eventName.substring(2);//firefox中所有的事件名称前面是没有on的。
element.addEventListener(eventName,new Function(methodName));
}
}
[解决办法]
附上源码,自己编译成类库吧
using System;using System.Collections.Generic;using System.ComponentModel;using System.Text;using System.Web;using System.Web.UI;using System.Web.UI.WebControls;namespace BlogLan.Web.Controls{ /// <summary> /// 表示一个防止重复提交的按钮。当用户单击按钮以后,该按钮变灰,不能再次单击,直到重新加载页面或者跳转。 /// </summary> [DefaultProperty("Text")] [ToolboxData("<{0}:ClickOnceButton runat=server></{0}:ClickOnceButton>")] public class ClickOnceButton : System.Web.UI.WebControls.Button { /// <summary> /// 默认的构造函数。 /// </summary> public ClickOnceButton() { this.ViewState["afterSubmitText"] = "正在提交,请稍候..."; base.Text = "ClickOnceButton"; this.ViewState["showMessageBox"] = false; this.ViewState["warningText"] = "确定要提交吗?"; } /// <summary> /// 获取或设置单击按钮后,按钮上所显示的文本。 /// </summary> [Bindable(true), Category("Appearance"), DefaultValue("正在提交,请稍候..."), Description("指示单击提交后,按钮上所显示的文本。")] public string AfterSubmitText { get { string afterSubmitText = (string)this.ViewState["afterSubmitText"]; if (afterSubmitText != null) { return afterSubmitText; } else { return string.Empty; } } set { this.ViewState["afterSubmitText"] = value; } } [Bindable(true), Category("Appearance"), DefaultValue(false), Description("指示是否要显示一个提示框。")] public bool ShowMessageBox { get { return (bool)this.ViewState["showMessageBox"]; } set { this.ViewState["showMessageBox"] = value; } } [Bindable(true), Category("Appearance"), DefaultValue("确定要提交吗?"), Description("指示提示框内所包含的内容。")] public string WarningText ; { get { return (string)this.ViewState["warningText"]; } set { this.ViewState["warningText"] = value; } } /// <summary> /// AddAttributesToRender /// </summary> /// <param name="writer">HtmlTextWriter</param> protected override void AddAttributesToRender(HtmlTextWriter writer) { System.Text.StringBuilder ClientSideEventReference = new System.Text.StringBuilder(); if (((this.Page != null) && this.CausesValidation) && (this.Page.Validators.Count > 0)) { ClientSideEventReference.Append("if (typeof(Page_ClientValidate) == 'function'){if (Page_ClientValidate() == false){return false;}}"); } //ShowMessageBox? if (this.ShowMessageBox) { ClientSideEventReference.Append("if (!confirm('" + this.WarningText + "')){return false}"); } ClientSideEventReference.AppendFormat("this.value = '{0}';", (string)this.ViewState["afterSubmitText"]); ClientSideEventReference.Append("this.disabled = true;"); ClientSideEventReference.Append(this.Page.ClientScript.GetPostBackEventReference(this, string.Empty)); writer.AddAttribute(HtmlTextWriterAttribute.Onclick, ClientSideEventReference.ToString(), true); base.AddAttributesToRender(writer); } }}