QuickLee
2008年期待改变!

    在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键值就可以了。

    为了尽可能地降低Session数据对服务器资源的占用量,现将上述方案略做调整,将ViewState利用md5加密后返回的32位字符串写入Session。
 
    另外,由于本方法会生成额外的Session占用服务器资源,所以请在必须保留当前页面状态的情况下使用,若无需保留当前页面状态,则在完成数据提交后直接重定向到当前页面即可。

Refresh是针对上述分析写的一个继承自System.Web.UI.Page的基类,需要防止刷新重复提交数据的页面从该基类继承,源码如下:

using System;
using System.Collections.Generic;
using System.Text;

namespace GuoTai.Lizm.CustomControlLibrary
{
    public class Refresh : System.Web.UI.Page
    {
        private string _strSessionKey;
        private string _hiddenfieldName;
        private string _strLastViewstate;

        public Refresh()
        {
            _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");
        }
    }
}
将要刷新的页面继承Refresh类,在设计视图中添加一个按钮,设断点调试,点击按钮就可以看到效果.
posted on 2007-04-24 15:15  清晨风  阅读(1696)  评论(2编辑  收藏  举报