SubmitOncePage:解决刷新页面造成的数据重复提交

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键值就可以了。  
   
         
oop80Edward.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
、设置Label1Text0  
          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.txtb.txt文件,可看到if   (!this.IsRefreshed)   的具体效果

 

 

注:把cs类编译成dll文件,需要用到.Framework的csc编译命令。

1. 我们要知道.Framework在哪里,他默认安装在c:WINDOWSMicrosoft.NETFramework 里面,然后你的framework有很多版本,你选择一个版本,我的是v2.0.50727,所以我的编译器csc在c:WINDOWSMicrosoft.NETFrameworkv2.0.50727里面。

2. 在dos输入以上framework路径后,使用命令csc   /target:library  /out:【你将要编译成的dll的路径】【你的cs类的路径】。
    例子:csc   /target:library  /out:F:Asp.net程序测试Asp.net程序调试binupload.dll   F:Asp.net程序测试Asp.net程序调试upload.cs

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值