用过ASP.NET的都知道,按钮操作之后会得到一个新的页面,然后用户通过浏览器的回退按钮可以回到原来的页面时,或者点刷新按钮刷新当前页面时,会显示对话框"不重新发送信息,则无法刷新页面",然后就有个"重试","取消"按钮,通常用户为了刷新页面而点击"重试",这样一点问题就来了,那么页面就会重复发送信息,并且执行先前按钮的操作,比如按钮是添加一行数据,那么刷新之后就会添加重复的数据.好的程序或许会报个提示说什么不能重复添加,甚至出个异常,没有限制的程序可能就任由用户重复的添加数据.这样当然是开发人员不想发生的,除非有极端的用户需求.
最近学了下HttpModule的内容,可用来解决这个问题.
这里利用HttpModule在页面请求之前,做一些操作,用一些标记标识每个请求的页面,程序如下,相互学习下.
首先有个类继承IHttpModule

NoRepeatOperModule
1
public class NoRepeatOperModule : IHttpModule
2
{
3
/**//// <summary>
4
/// 保存访问的页面记录,以页面路径为key, 标号为value
5
/// </summary>
6
static Hashtable historyRequest = null;
7
8
/**//// <summary>
9
/// 请求路径
10
/// </summary>
11
private string RequestPath
12
{
13
get
14
{
15
return HttpContext.Current.Request.Path;
16
}
17
}
18
19
IHttpModule 成员#region IHttpModule 成员
20
21
public void Dispose()
22
{
23
//throw new Exception("The method or operation is not implemented.");
24
}
25
26
public void Init(HttpApplication context)
27
{
28
if (historyRequest == null)
29
{
30
historyRequest = new Hashtable();
31
}
32
33
context.BeginRequest += delegate(object sender, EventArgs e)
34
{
35
int lastTicket = GetLastTicket();
36
int currentTicket = GetCurrentTicket(lastTicket);
37
38
// 比较当前标号和上一个的标号,判断页面请求是否来源于刷新操作
39
// 当前标号大于上一个标号 或初次请求都属于新的页面
40
if (currentTicket > lastTicket || (lastTicket == currentTicket && currentTicket == 0))
41
{
42
// 标记并保存页面请求是否来源于刷新的bool值
43
HttpContext.Current.Items[RequestPath + "_IsRefreshed"] = false;
44
historyRequest[RequestPath] = currentTicket;
45
}
46
else
47
{
48
HttpContext.Current.Items[RequestPath + "_IsRefreshed"] = true;
49
}
50
};
51
}
52
53
#endregion
54
55
/**//// <summary>
56
/// 获取某页面的上一个标号
57
/// </summary>
58
/// <returns></returns>
59
private int GetLastTicket()
60
{
61
if (!historyRequest.ContainsKey(RequestPath))
62
{
63
return 0;
64
}
65
66
return int.Parse(historyRequest[RequestPath].ToString());
67
}
68
69
/**//// <summary>
70
/// 获取页面的当前标号
71
/// </summary>
72
/// <param name="lastTicket">上一个标号</param>
73
/// <returns></returns>
74
private int GetCurrentTicket(int lastTicket)
75
{
76
int ticket;
77
// CurrentTicket 为页面的隐藏域的内容
78
string currentTicket = HttpContext.Current.Request["CurrentTicket"];
79
if (currentTicket == null)
80
{
81
ticket = lastTicket;
82
}
83
else
84
{
85
ticket = int.Parse(currentTicket);
86
}
87
88
// 保存页面的下一个标号
89
HttpContext.Current.Items[RequestPath + "_NextTicket"] = ticket + 1;
90
return ticket;
91
}
92
}
第二步,在web.config中配置自定义的HttpModule

Web.Config配置
1
<system.web>
2
<httpModules>
3
<add name="NoRepeatOperModule" type="AspAdvance1.NoRepeatOperModule, AspAdvance1"/>
4
</httpModules>
5
</system.web>
最后还要在asp.cs文件中处理如下,加个属性IsRefreshed,重写基类的
OnPreRenderComplete,最后调用在
btnTest_Click
其实可以吧以下作为自定义的Page类,其他页面继承即可

具体页面实现
1
public partial class _Default : System.Web.UI.Page
2
{
3
/**//// <summary>
4
/// 页面请求是否来源于页面刷新
5
/// </summary>
6
private bool IsRefreshed
7
{
8
get
9
{
10
string requestPath = HttpContext.Current.Request.Path;
11
return (bool)HttpContext.Current.Items[requestPath + "_IsRefreshed"];
12
}
13
}
14
15
/**//// <summary>
16
/// 重写OnPreRenderComplete,生成隐藏域CurrentTicket
17
/// </summary>
18
/// <param name="e"></param>
19
protected override void OnPreRenderComplete(EventArgs e)
20
{
21
base.OnPreRenderComplete(e);
22
string requestPath = HttpContext.Current.Request.Path;
23
int ticket = int.Parse(HttpContext.Current.Items[requestPath + "_NextTicket"].ToString());
24
ClientScript.RegisterHiddenField("CurrentTicket", ticket.ToString());
25
}
26
27
protected void btnTest_Click(object sender, EventArgs e)
28
{
29
// 根据IsRefreshed 判断页面请求是否来源于刷新来 判断是否进行操作
30
if (!IsRefreshed)
31
{
32
using (StreamWriter sw = new StreamWriter("E:\\test.txt", true))
33
{
34
sw.WriteLine(DateTime.Now.ToString());
35
}
36
}
37
}
38
}
点击btnTest之后会写入一行,此时页面重新生成,点刷新或回退,再点"重试",将不会重复原来的操作.