web开发中经常遇到的一个问题是,如何禁止重复提交。一个通用的场景是,页面上有一个Save button,点击后,将会将表单纪录保存到数据库中。但是此后如果用户按F5刷新页面的话,程序中如果不做任何处理,就会导致数据库存储重复纪录。然而实际的场景是,作为开发人员我们不能限制用户刷新页面,因此我们需要寻找一种机制来判断页面是由于control的PostBack还是用户的F5刷新重新render()?
关于这个问题,在MSDN上作者提供了一种机制,可以用来判断用户刷新,原文参见:http://msdn2.microsoft.com/en-us/library/ms379557(VS.80).aspx
下面介绍一种更简单的方法,使用页面的ViewState机制来实现。
- 页面初始加载间段页面生存期中的主要事件
- 页面PostBack和返回过程中页面生存期中的主要事件
- LoadViewState:
-
SaveViewState
- 从图中可以看出,LoadViewState是页面初始化过程的一部分,只有在PostBack后才会被调用,我们可以通过判断先前的ViewState的值与session中对应的值是否一样,来判断用户是否刷新了页面,代码如下:
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
/**//// <summary>
/// Summary description for RefreshDetectPage
/// </summary>
public class RefreshDetectPage:System.Web.UI.Page
...{
public RefreshDetectPage()
...{
//
// TODO: Add constructor logic herej
//
}
private bool _refreshState=false;
private bool _isRefresh=false;
public bool IsRefresh
...{
get ...{ return _isRefresh; }
}
protected override void LoadViewState(object savedState)
...{
object[] states = (object[])savedState;
base.LoadViewState(states[0]);
_refreshState = Boolean.Parse(states[1].ToString());
_isRefresh = (_refreshState.ToString() == Session["IS_Refresh_Key"].ToString());
}
protected override object SaveViewState()
...{
HttpContext.Current.Session["IS_Refresh_Key"] = _refreshState;
object[] states=new object[2];
states[0] = base.SaveViewState();
states[1] = !_refreshState;
return states;
}
}
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
/**//// <summary>
/// Summary description for RefreshDetectPage
/// </summary>
public class RefreshDetectPage:System.Web.UI.Page
...{
public RefreshDetectPage()
...{
//
// TODO: Add constructor logic herej
//
}
private bool _refreshState=false;
private bool _isRefresh=false;
public bool IsRefresh
...{
get ...{ return _isRefresh; }
}
protected override void LoadViewState(object savedState)
...{
object[] states = (object[])savedState;
base.LoadViewState(states[0]);
_refreshState = Boolean.Parse(states[1].ToString());
_isRefresh = (_refreshState.ToString() == Session["IS_Refresh_Key"].ToString());
}
protected override object SaveViewState()
...{
HttpContext.Current.Session["IS_Refresh_Key"] = _refreshState;
object[] states=new object[2];
states[0] = base.SaveViewState();
states[1] = !_refreshState;
return states;
}
}
- 使用的时候,需要把code behind的Page改为从RefreshDetectPage继承,通过
- 访问基类的IsRefresh属性来判断。
- 第一次请求:
点击control引起页面回发:
F5刷新: