欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

ASP.NET防止页面刷新的两种解决方法小结

程序员文章站 2024-02-25 23:01:21
方法有二,总结如下: 第一方法: 直接在cs代码里敲: response.buffer = true; response.expiresabsolute = datet...

方法有二,总结如下:

第一方法:
直接在cs代码里敲:
response.buffer = true;
response.expiresabsolute = datetime.now.addseconds(-1);
response.expires = 0;
response.cachecontrol = "no-cache";

当有人想按后退时页面已过期,效果就达到了

第二方法:
submitoncepage:解决刷新页面造成的数据重复提交问题(网上资料)

执行过postback操作的web页面在刷新的时候,浏览器会有“不重新发送信息,则无法刷新网页”的提示,若刚刚执行的恰好是往数据库插入一条新记录的操作,点[重试]的结果是插入了两条重复的记录,以前一直是用保存数据后重新转向当前页面的方法解决,最近又找到了一个新的方法。

问题分析

在system.web.ui.page类中,有一个名为viewstate属性用以保存页面的当前视图状态,观察每个aspx页面最终生成的html代码可以发现,其实就是向页面添加了一个名为__viewstate的隐藏域,其value值就是页面的当前状态,每次执行postback过后,该 value值都会发生变化,而刷新页面则不会改变。

针对这种情况,我们可以在页面代码执行的末尾将当前的viewstate写到一个session中,而在页面加载时则判断该session值是否与当前 viewstate相等(其实session值恰好是viewstate的前一状态),若不等,则是正常的postback,若是相等则是浏览器刷新,这样一来,只要在我们的数据插入代码外嵌套一个if判断就可以达到防止数据重复提交的目的了。

其实到这里问题还没有完全解决,具体说来就是session的键值问题。假设我们将viewstate保存为 this.session["myviewstate"],如果一个用户同时打开两个防刷新提交的页面就乱套了,那针对页面的url设置session的键值呢?还是不行,因为用户有可能在两个窗口中打开同一页面,所以必须为每次打开的页面定义唯一的session键值,并且该键值可以随当前页面实例一起保存,参考viewstate的保存方式,我们直接向页面添加一个隐藏域专门存放session键值就可以了。

经oop80和edward.net的提醒,为了尽可能地降低session数据对服务器资源的占用量,现将上述方案略做调整,将viewstate利用md5加密后返回的32位字符串写入session。

另外,由于本方法会生成额外的session占用服务器资源,所以请在必须保留当前页面状态的情况下使用,若无需保留当前页面状态,则在完成数据提交后直接重定向到当前页面即可。

submitoncepage

submitoncepage是针对上述分析写的一个继承自system.web.ui.page的基类,需要防止刷新重复提交数据的页面从该基类继承,源码如下:

复制代码 代码如下:

namespace mycontrol
{
/// <summary>
/// 名称:submitoncepage
/// 父类:system.web.ui.page
/// 描述:解决浏览器刷新造成的数据重复提交问题的page扩展类。
/// 示例:if (!this.isrefreshed)
///{
/////具体代码
///}
/// </summary>
public class submitoncepage:system.web.ui.page
{
private string _strsessionkey;
private string _hiddenfieldname;
private string _strlastviewstate;

public submitoncepage()
{
_hiddenfieldname = "__lastviewstate_sessionkey";
_strsessionkey = system.guid.newguid().tostring();
_strlastviewstate = string.empty;
}

public bool isrefreshed
{
get
{
string str1 = getsessincontent();
_strlastviewstate = str1;
string str2 = this.session[getsessinkey()] as string;
bool flag1 = (str1 != null) && (str2 != null) && (str1 == str2);
return flag1;
}
}

protected override void render(system.web.ui.htmltextwriter writer)
{
string str = getsessinkey();
this.session[str] = _strlastviewstate;
this.registerhiddenfield(_hiddenfieldname, str);
base.render(writer);
}


private string getsessinkey()
{
string str = this.request.form[_hiddenfieldname];
return (str == null) ? _strsessionkey : str;
}

private string getsessincontent() {
string str = this.request.form["__viewstate"];
if (str == null) {
return null;
}
return system.web.security.formsauthentication.hashpasswordforstoringinconfigfile(str, "md5");
}

}
}


测试项目

首先将submitoncepage类的源码编译成一个单独的dll,然后进行测试,步骤如下:

1、新建一个asp.net web应用程序;
2、添加submitoncepage类对应的dll引用;
3、给webform1添加一个label控件(label1)和一个button控件(button1);
4、设置label1的text为0;
5、双击button1转到codebehind视图;
6、修改类webform1的父类为submitoncepage并添加测试代码,结果如下:

复制代码 代码如下:

public class webform1 : mycontrol.submitoncepage
{
protected system.web.ui.webcontrols.label label1;
protected system.web.ui.webcontrols.button button1;


#region web 窗体设计器生成的代码
override protected void oninit(eventargs e)
{
//
// codegen: 该调用是 asp.net web 窗体设计器所必需的。
//
initializecomponent();
base.oninit(e);
}

/// <summary>
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
/// </summary>
private void initializecomponent()
{
this.button1.click += new system.eventhandler(this.button1_click);
}
#endregion

private void button1_click(object sender, system.eventargs e)
{
int i=int.parse(label1.text)+1;
label1.text = i.tostring();
if (!this.isrefreshed)
{
writefile("a.txt", i.tostring());
}
writefile("b.txt", i.tostring()); 


}

private void writefile(string strfilename,string strcontent)
{
string str = this.server.mappath(strfilename); 
system.io.streamwriter sw = system.io.file.appendtext(str);
sw.writeline(strcontent);
sw.flush();
sw.close(); 
}
}


7、按f5运行,在浏览器窗口中连续点击几次button1,然后刷新几次页面,再点击几次button1;

8、转到测试项目对应目录下,打开a.txt和b.txt文件,可看到if (!this.isrefreshed) 的具体效果。