网络安全

位置:IT落伍者 >> 网络安全 >> 浏览文章

一步步打造防止重复提交按钮


发布日期:2019年12月06日
 
一步步打造防止重复提交按钮
首先说说防止重复提交按钮是啥东西

我们在访问有的网站输入表单完成以后单击提交按钮进行提交以后提交按钮就会变为灰色用户不能再单击第二次直到重新加载页面或者跳转这样可以一定程度上防止用户重复提交导致应用程序上逻辑错误有朋友说这个按钮完全可以用js来做是的不过当你需要大量这种按钮时是否为每一个都去编程而不封装一个呢?

另外为了增加其功能性我们除了让他有防止重复提交的功能以外还可以给他弹出提示框就像单击删除按钮时用户会受到一个提示再次确认是否真的删除

接下来第一步知识储备

我们知道要防止重复提交要在客户端设法使用户单击一次以后按钮变灰这种客户端行为显然只能借助js代码来完成服务器端运行的ASPNET是做不到的那要让客户端用户单击按钮后立即收到一条再次确认消息在确认之前不会提交到服务器也需要js代码因此我们基本的丝路就是在页面加载按钮时一并把所需的js代码发送到客户端去而该按钮都是适用js脚本因此不影响服务器端行为

第二步从Button继承

因为它是一个按钮拥有按钮所需要的全部特征属性因此我们就从SystemWebUIWebControlsButton这个类继承而防止重复提交按钮在按钮变成灰色以后应该显示什么文本呢?新增一个AfterSubmitText属性来指示采用一个Bool值ShowMessageBox属性来确定是否需要在客户端弹出提示使用WarningText属性来指示客户端弹出提示的内容

第三步

现在我们就来改写AddAttributesToRender方法ASPNET在渲染该控件到输出时会调用该方法我们所改写的方法以达到将JS代码发送到客户端的目的具体代码如下

protected override void AddAttributesToRender(HtmlTextWriter writer)

{

SystemTextStringBuilder ClientSideEventReference = new SystemTextStringBuilder()

if (((thisPage != null) && thisCausesValidation) && (thisPageValidatorsCount > ))

{

ClientSideEventReferenceAppend(if (typeof(Page_ClientValidate) == function){if (Page_ClientValidate() == false){return false;}}

}

//ShowMessageBox?

if (thisShowMessageBox)

{

ClientSideEventReferenceAppend(if (!confirm( + thisWarningText + )){return false}

}

ClientSideEventReferenceAppendFormat(thisvalue = {}; (string)thisViewState[afterSubmitText])

ClientSideEventReferenceAppend(thisdisabled = true;

ClientSideEventReferenceAppend(thisPageClientScriptGetPostBackEventReference(this stringEmpty))

writerAddAttribute(HtmlTextWriterAttributeOnclick ClientSideEventReferenceToString() true)

baseAddAttributesToRender(writer)

}

我们把发送到客户端的js代码看作是一个字符串为了提高性能用StringBuilder来对象来构造这个字符串

首先根据页面对象存在且控件启用了验证(该属性从父继承)且页面对象的验证器内计数大于来决定输出一段引发验证的js代码

根据ShowMessageBox属性来决定输出一个弹出提示的代码并且弹出提示的内容由WarningText属性给出

书写一个js脚本为按钮赋值为提交后文本并且将按钮设置为禁用以变灰色

最后附加一段由ASPNET提供的用于影射回调事件引用的js脚本(thisPageClientScriptGetPostBackEventReference(this stringEmpty)方法将返回一个回送事件引用的js脚本字符串)

将StringBuilder对象内构造的字符串用HtmlTextWriter对象的AddAttribute方法写入按钮的OnClick事件中

调用父类的AddAttributesToRender方法让父类有机会完成其他的配置等操作

完整的ClickOnceButton代码如下

using System;

using SystemCollectionsGeneric;

using SystemComponentModel;

using SystemText;

using SystemWeb;

using SystemWebUI;

using SystemWebUIWebControls;

namespace BlogLanWebControls

{

/// <summary>

/// 表示一个防止重复提交的按钮当用户单击按钮以后该按钮变灰不能再次单击直到重新加载页面或者跳转

/// </summary>

[DefaultProperty(Text)]

[ToolboxData(<{}:ClickOnceButton runat=server></{}:ClickOnceButton>)]

public class ClickOnceButton : SystemWebUIWebControlsButton

{

/// <summary>

/// 默认的构造函数

/// </summary>

public ClickOnceButton()

{

thisViewState[afterSubmitText] = 正在提交请稍候…;

baseText = ClickOnceButton;

thisViewState[showMessageBox] = false;

thisViewState[warningText] = 确定要提交吗?;

}

/// <summary>

/// 获取或设置单击按钮后按钮上所显示的文本

/// </summary>

[Bindable(true)

Category(Appearance

DefaultValue(正在提交请稍候…

Description(指示单击提交后按钮上所显示的文本)]

public string AfterSubmitText

{

get

{

string afterSubmitText = (string)thisViewState[afterSubmitText];

if (afterSubmitText != null)

{

return afterSubmitText;

}

else

{

return stringEmpty;

}

}

set

{

thisViewState[afterSubmitText] = value;

}

}

[Bindable(true)

Category(Appearance

DefaultValue(false)

Description(指示是否要显示一个提示框)]

public bool ShowMessageBox

{

get

{

return (bool)thisViewState[showMessageBox];

}

set

{

thisViewState[showMessageBox] = value;

}

}

[Bindable(true)

Category(Appearance

DefaultValue(确定要提交吗?

Description(指示提示框内所包含的内容)]

public string WarningText

{

get

{

return (string)thisViewState[warningText];

}

set

{

thisViewState[warningText] = value;

}

}

/// <summary>

/// AddAttributesToRender

/// </summary>

/// <param name=writer>HtmlTextWriter</param>

protected override void AddAttributesToRender(HtmlTextWriter writer)

{

SystemTextStringBuilder ClientSideEventReference = new SystemTextStringBuilder()

if (((thisPage != null) && thisCausesValidation) && (thisPageValidatorsCount > ))

{

ClientSideEventReferenceAppend(if (typeof(Page_ClientValidate) == function){if (Page_ClientValidate() == false){return false;}}

}

//ShowMessageBox?

if (thisShowMessageBox)

{

ClientSideEventReferenceAppend(if (!confirm( + thisWarningText + )){return false}

}

ClientSideEventReferenceAppendFormat(thisvalue = {}; (string)thisViewState[afterSubmitText])

ClientSideEventReferenceAppend(thisdisabled = true;

ClientSideEventReferenceAppend(thisPageClientScriptGetPostBackEventReference(this stringEmpty))

writerAddAttribute(HtmlTextWriterAttributeOnclick ClientSideEventReferenceToString() true)

baseAddAttributesToRender(writer)

}

}

}

你可以把它编译为dll放置在工具箱中随意拖放到网页上即可使用因为继承了Button控件它拥有Button的全部特性并且自动继承了Button的设计时支持

后记

当我决定自己开发自定义控件时这是我第一个想到的因为明确它就是在一个Button控件基础上并用JS代码来实现功能因此它应该是一个比较简单的东西了

代码贴出来与各位分享尽管现在新技术层出不穷用AJAX也可以达到效果不过假如你只是想要防止重复提交也不用劳烦AJAX这个沉重的框架来完成有点杀鸡用牛刀了

愿各位朋友举一反三深入探讨               

上一篇:Acegi安全系统的配置

下一篇:Raw Socket编程实现网络封包监视