2004-12-29+ “Detecting Page Refresh”的分析
“Detecting Page Refresh”(我的dote blog里)里介绍了一种判断用户刷新的办法,不错,可以其中的原理确着实让我头痛了好一会,不过现在终于想明白了,写到这里,大家看看看是不是这么回事
里面说用重写loadviewstate和saveviewstate两个方法来实现变量值的改变,如果大家把代码写到vs里调试一下就会发现,不论是refresh还是postback,程序的流程都是一样,即:先走一遍loadviewstate,然后走两遍saveviewstate,既然是一样的,那为什么得出得结果却不相同?原因就在于:当你postback的时候,saveviewstate中的数据就被提交到服务器,可是当你refresh的时候,saveviewstate的数据并没有被提交,这样导致的结果就是allStates[1]的值的不同,在postback的时候,loadviewstate中使用的是这次返回的allStates[1],可是refresh的时候,loadviewstate中使用的是上次返回的allStates[1]。
_refreshState和_isRefresh在每次的初始值都是false,下面是两个流程的分析:
postback前发生的SaveViewState
protected override object SaveViewState()
{
//Session["__ISREFRESH"]的值为false
Session["__ISREFRESH"] = _refreshState;
object[] allStates = new object[2];
allStates[0] = base.SaveViewState();
//allStates[1]的值为true
allStates[1] = !_refreshState;
return allStates;
}
用户postback
先引发LoadViewState
protected override void LoadViewState(object savedState)
{
object[] allStates = (object[]) savedState;
base.LoadViewState(allStates[0]);
//allStates[1]的值为true,所以_refrehState也为true
_refrehState = (bool) allStates[1];
//true和false相比,所以_isRefresh为false
_isRefresh = _refreshState == (bool) Session["__ISREFRESH"];
}
紧接着进入SaveViewState
//postback后发生的SaveViewState
protected override object SaveViewState()
{
//_refreshState在loadviewstate中被改为true,所以Session["__ISREFRESH"]的值为true
Session["__ISREFRESH"] = _refreshState;
object[] allStates = new object[2];
allStates[0] = base.SaveViewState();
//allStates[1]的值为false
allStates[1] = !_refreshState;
return allStates;
}
然后用户refresh,进入LoadViewState
protected override void LoadViewState(object savedState)
{
object[] allStates = (object[]) savedState;
base.LoadViewState(allStates[0]);
//allStates[1]使用前一次的值,即true
_refrehState = (bool) allStates[1];
//这里Session["__ISREFRESH"]也是true,所以_isRefresh的值变成true
_isRefresh = _refreshState == (bool) Session["__ISREFRESH"];
}
这样说是有点糊涂,汗……不知该怎样表达,但是这个过程如果放到vs里进行一下单步调试,则配合上面的过程,应该就很容易看出了。
最后说一下实际应用,当然是先创建一个继承自System.Web.UI.Page的PageBase,然后在PageBase内重写那两个方法,最后让需要使用该功能的页面继承PageBase。
2005-2-27 bug补充
//描述:当打开一个有提交按钮的页面,点击按钮提交,出现错误
// 异常详细信息: System.NullReferenceException: 未将对象引用设置到对象的实例。
// 源错误:
// 行 29: base.LoadViewState(states[0]);
// 行 30: this.refreshState=(bool)states[1];
// 行 31: this.isRefresh=(this.refreshState==(bool)Context.Session["isRefresh"]);
// 行 32: }
//原因是提交时Session["isRefresh"]不存在
// 可能的情况是停留时间太长导致session失效,或进行了错误的操作导致session失效
// 当postback时,页面会先进入LoadViewState(),然后进入SaveViewState()
//当Session["isRefresh"]为null时进入LoadViewState()自然引发异常
//解决办法就是确保在每次页面初始化时Session["isRefresh"]不为空
protected override void OnInit(EventArgs e)
{
base.OnInit (e);
if(Context.Session["isRefresh"]==null)
Context.Session["isRefresh"]=false;