Asp.Net防止多次提交数据(转)
作者:C/S原创  发布日期:2011/03/17 23:28:52

Asp.Net防止多次提交数据


RefreshAction类:

public static class RefreshAction
{
   // 常量
   //服务端票证key
   
   public const string LastRefreshTicketEntry = "__LASTREFRESHTICKET"; //客户端票证key
   public const string CurrentRefreshTicketEntry = "__CURRENTREFRESHTICKET"; //用来保存是否是重复刷新的属性的key
   public const string PageRefreshEntry = "IsPageRefresh"; // 检测F5按钮是否被按下
   
   public static void Check(HttpContext ctx)
   {
      //初始化服务端票证
      EnsureRefreshTicket(ctx); //从Session里读取上一次提供的票证
      
      int lastTicket = GetLastRefreshTicket(ctx); //从请求里的隐藏域里读取当前页面的票证
      int thisTicket = GetCurrentRefreshTicket(ctx); // 对比两个票证
      if (thisTicket != lastTicket || (thisTicket == lastTicket && thisTicket == 0))
      {
         //如果当前的票证值大于上一次的票证值 或者
         //当前票证值等于上一次票证值,并且当前票证值为0(这是第一次刷新)
         //那么更新Session里上一次的票证值为当前票证值
         UpdateLastRefreshTicket(ctx, thisTicket); //设置当前页是否重复刷新属性为false
         ctx.Items[PageRefreshEntry] = false;
      }
      else
      {
         //设置当前页是否重复刷新属性为true;
         ctx.Items[PageRefreshEntry] = true;
      }
   }
   
   //确认上一次的票证不为空值
   private static void EnsureRefreshTicket(HttpContext ctx)
   {
      // Initialize the session slots for the page (Ticket) and the module (LastTicketServed)
      //初始化Session的最后一次票证值
      if (ctx.Session[LastRefreshTicketEntry] == null)
      ctx.Session[LastRefreshTicketEntry] = 0;
      
   }
   
   //从Session里得到上一次请求的票证值
   private static int GetLastRefreshTicket(HttpContext ctx)
   { //返回Session里保存的上一次票证值
   return Convert.ToInt32(ctx.Session[LastRefreshTicketEntry]);
}


//从当前请求里的到隐藏域里保存的当前票证值
private static int GetCurrentRefreshTicket(HttpContext ctx)
{
   return Convert.ToInt32(ctx.Request[CurrentRefreshTicketEntry]);
}

// 将当前的票证值保存到Session里的上一次刷新的票证值
private static void UpdateLastRefreshTicket(HttpContext ctx, int ticket)
{
   ctx.Session[LastRefreshTicketEntry] = ticket;
}
}

// 来源:www.CSFramework.com, C/S结构框架学习网




RefreshModule 类:

//Provides module initialization and disposal events to the implementing class
public class RefreshModule : IHttpModule
{
   //初始化模块
   public void Init(HttpApplication app)
   { // Register for pipeline events
   //注册请求关联状态时的事件处理器,就是说当一个请求到达服务器,
   //那么首先触发这个事件,由OnAcquireRqeustState事件处理
   app.AcquireRequestState = new EventHandler(this.OnAcquireRequestState);
}

// IHttpModule::Dispose
public void Dispose() { }

//判断是否是F5或前进/后退操作
private void OnAcquireRequestState(object sender, EventArgs e)
{
   //得到访问的HTTP上下文
   HttpApplication app = (HttpApplication)sender;
   HttpContext ctx = app.Context; //检查是否是F5操作
   if (ctx != null && ctx.Session != null)
   RefreshAction.Check(ctx);
   return;
}
}

// 来源:www.CSFramework.com, C/S结构框架学习网



定义一个基类,所有提交数据的页面继承:SubmitOncePage

public class SubmitOncePage : PageBaseRefreshCounter
{
   
   #region Constants
   // 常量
   public const string RefreshTicketCounter = "RefreshTicketCounter";
   #endregion
   
   // Ctor
   
   public SubmitOncePage()
   {
      // Register a PreRender handler
      //注册页面呈现前的事件处理器
      this.PreRender = new EventHandler(RefreshPage_PreRender);
      
   }
   
   //标志页面是否按F5进行重复刷新的标志属性
   public bool IsPageRefresh
   {
      get
      {
         object o = HttpContext.Current.Items[RefreshAction.PageRefreshEntry];
         if (o == null)
         return false;
         return (bool)o;
      }
      set
      {
         object o = HttpContext.Current.Items[RefreshAction.PageRefreshEntry];
         if (o != null)
         HttpContext.Current.Items[RefreshAction.PageRefreshEntry] = false;
      }
   }
   
   //增加刷新票证的内部计数器
   public void TrackRefreshState()
   { //初始化刷新计数器
   InitRefreshState();
   //将刷新计数器加1,然后放进Session
   int ticket = Convert.ToInt32(Session[RefreshTicketCounter]) 1;
   Session[RefreshTicketCounter] = ticket;
}


#region Private Members
// Create the hidden field to store the current request ticket
//创建隐藏域来保存当前请求的票证值

private void SaveRefreshState()
{
   //将票证计数器的值加1,然后将此值注册到当前票证隐藏域中
   int ticket = Convert.ToInt32(Session[RefreshTicketCounter]) 1;
   this.ClientScript.RegisterHiddenField(RefreshAction.CurrentRefreshTicketEntry, ticket.ToString());
}

//初始化刷新计数器
private void InitRefreshState()
{
   if (Session[RefreshTicketCounter] == null)
   Session[RefreshTicketCounter] = 0;
}

// PreRender事件处理器
private void RefreshPage_PreRender(object sender, EventArgs e)
{
   //在页面呈现之前就保存票证值到隐藏域
   SaveRefreshState();
}

#endregion

}

// 来源:www.CSFramework.com, C/S结构框架学习网



最后在Web.Config文件内定义一个<httpModules>


  <system.web>

 

    <httpModules>

      <add name="CSFramework_RefreshModule" type="CSFramework.BLL.RefreshModule"/>

    </httpModules>

 





 

上一篇 下一篇