探讨对Web控件的异常处理
在使用ASP.NET时,常常使用Page的错误事件Error进行错误捕捉和处理。这种方式可以集中处理所有异常,这种方式有利有弊。集中处理的好处就不用啰嗦了,这里只说明一下这种方式的局限,就是当页面中的某个控件发生异常之后,整个页面执行都会中断,然后处理异常,这样一来,页面就无法显示。
在实际开发中,常常有这样的需求,即页面是由多个相对独立的控件组成,其中一个控件的错误不能影响到其它控件的正常显示。这就需要在控件内部捕捉错误,并自行处理错误,然而控件基类并没有提供这样的错误捕捉功能。如何用简单有效方法来实现呢?
其实我们可以实现一个基类,并把所有在控件生命期中会调用到的方法都封装起来,这样只要继承这个控件,就可以方便地实现在控件内部自行捕捉错误的功能。请看下面的代码:
1
public abstract class AbstractControl: Control
2
{
3
/// <summary>
4
/// 异常栈
5
/// </summary>
6
public Stack Exceptions
7
{
8
get
9
{
10
if (exceptions == null)
11
{
12
exceptions = new Stack();
13
}
14
return exceptions;
15
}
16
}
17
18
protected override void CreateChildControls()
19
{
20
try
21
{
22
CreateChildControlsByCatchedException();
23
}
24
catch (HttpUnhandledException)
25
{
26
throw;
27
}
28
catch (Exception ex)
29
408_436_Open_Image.style.display='inline'; Codehighlighter1_408_436_Open_Text.style.display='inline';" src="/Images/OutliningIndicators/ContractedSubBlock.gif" align=top> {
30
Exceptions.Push(ex);
31
}
32
}
33
34
/// <summary>
35
/// 创建子控件(已进行异常捕捉处理)
36
/// </summary>
37
protected virtual void CreateChildControlsByCatchedException()
38
{
39
}
40
41
/// <summary>
42
///
43
/// </summary>
44
/// <param name="e"></param>
45
protected override void OnPreRender(EventArgs e)
46
{
47
try
48
{
49
OnPreRenderByCatchedException(e);
50
}
51
catch (HttpUnhandledException)
52
{
53
throw;
54
}
55
catch (Exception ex)
56
{
57
Exceptions.Push(ex);
58
}
59
}
60
61
/// <summary>
62
/// 呈现前事件(已进行错误捕捉处理)
63
/// </summary>
64
/// <param name="e"></param>
65
protected virtual void OnPreRenderByCatchedException(EventArgs e)
66
{
67
base.OnPreRender (e);
68
}
69
70
/// <summary>
71
/// 设计时的呈现前事件
72
/// </summary>
73
/// <param name="e"></param>
74
protected virtual void DesigningOnPreRenderByCatchedException(EventArgs e)
75
{
76
}
77
78
/// <summary>
79
/// 呈现
80
/// </summary>
81
/// <param name="writer"></param>
82
protected override void Render(HtmlTextWriter writer)
83
{
84
if (Exceptions.Count > 0)
85
{
86
while (Exceptions.Count > 0 )
87
{
88
Exception ex = (Exception) Exceptions.Pop();
89
RenderException(writer, ex);
90
}
91
return;
92
}
93
94
try
95
{
96
RenderByCatchedException(writer);
97
}
98
catch (HttpUnhandledException)
99
{
100
throw;
101
}
102
catch (Exception ex)
103
{
104
RenderException(writer, ex);
105
}
106
}
107
108
/// <summary>
109
/// 呈现(已进行错误捕捉处理)
110
/// </summary>
111
/// <param name="writer"></param>
112
protected virtual void RenderByCatchedException(HtmlTextWriter writer)
113
{
114
base.Render (writer);
115
}
116
117
/// <summary>
118
/// 呈现异常
119
/// </summary>
120
/// <param name="writer"></param>
121
/// <param name="ex"></param>
122
private void RenderException(HtmlTextWriter writer, Exception ex)
123
{
124
writer.AddAttribute(HtmlTextWriterAttribute.Title, BuildExceptionInfomation(ex));
125
writer.AddStyleAttribute("font-weight", "700");
126
writer.AddStyleAttribute("color", "#f00");
127
writer.AddStyleAttribute("border", "1px solid #ddd");
128
writer.AddStyleAttribute("cursor", "pointer");
129
writer.AddStyleAttribute("padding", "0px 3px 0px 3px");
130
writer.AddStyleAttribute("background-color", "#ffe");
131
writer.RenderBeginTag(HtmlTextWriterTag.Span);
132
writer.Write("!");
133
writer.RenderEndTag();
134
}
135
136
/// <summary>
137
/// 生成异常信息
138
/// </summary>
139
/// <param name="ex"></param>
140
/// <returns></returns>
141
private string BuildExceptionInfomation(Exception ex)
142
{
143
StringBuilder sb = new StringBuilder();
144
sb.Append(ex.Message);
145
sb.Append(Environment.NewLine);
146
sb.Append(ex.GetType().FullName);
147
sb.Append(Environment.NewLine);
148
sb.Append(ex.StackTrace);
149
return sb.ToString();
150
}
151
152
/// <summary>
153
/// 中断程序的执行
154
/// </summary>
155
/// <param name="ex"></param>
156
protected virtual void Interrupt(Exception ex)
157
{
158
throw new HttpUnhandledException(ex.Message, ex);
159
}
160
}
161
public abstract class AbstractControl: Control2
{3
/// <summary>4
/// 异常栈5
/// </summary> 6
public Stack Exceptions7
{8
get9
{10
if (exceptions == null)11
{12
exceptions = new Stack();13
}14
return exceptions;15
}16
}17

18
protected override void CreateChildControls()19
{20
try21
{22
CreateChildControlsByCatchedException();23
}24
catch (HttpUnhandledException)25
{26
throw;27
}28
catch (Exception ex)29
408_436_Open_Image.style.display='inline'; Codehighlighter1_408_436_Open_Text.style.display='inline';" src="/Images/OutliningIndicators/ContractedSubBlock.gif" align=top> {30
Exceptions.Push(ex);31
}32
}33

34
/// <summary>35
/// 创建子控件(已进行异常捕捉处理)36
/// </summary>37
protected virtual void CreateChildControlsByCatchedException()38
{39
}40

41
/// <summary>42
/// 43
/// </summary>44
/// <param name="e"></param>45
protected override void OnPreRender(EventArgs e)46
{47
try48
{49
OnPreRenderByCatchedException(e);50
}51
catch (HttpUnhandledException)52
{53
throw;54
}55
catch (Exception ex)56
{57
Exceptions.Push(ex);58
}59
}60

61
/// <summary>62
/// 呈现前事件(已进行错误捕捉处理)63
/// </summary>64
/// <param name="e"></param>65
protected virtual void OnPreRenderByCatchedException(EventArgs e)66
{67
base.OnPreRender (e);68
}69
70
/// <summary>71
/// 设计时的呈现前事件72
/// </summary>73
/// <param name="e"></param>74
protected virtual void DesigningOnPreRenderByCatchedException(EventArgs e)75
{76
}77

78
/// <summary>79
/// 呈现80
/// </summary>81
/// <param name="writer"></param>82
protected override void Render(HtmlTextWriter writer)83
{84
if (Exceptions.Count > 0)85
{86
while (Exceptions.Count > 0 )87
{88
Exception ex = (Exception) Exceptions.Pop();89
RenderException(writer, ex);90
}91
return;92
}93
94
try95
{96
RenderByCatchedException(writer);97
}98
catch (HttpUnhandledException)99
{100
throw;101
}102
catch (Exception ex)103
{104
RenderException(writer, ex);105
}106
}107

108
/// <summary>109
/// 呈现(已进行错误捕捉处理)110
/// </summary>111
/// <param name="writer"></param>112
protected virtual void RenderByCatchedException(HtmlTextWriter writer)113
{114
base.Render (writer);115
}116

117
/// <summary>118
/// 呈现异常119
/// </summary>120
/// <param name="writer"></param>121
/// <param name="ex"></param>122
private void RenderException(HtmlTextWriter writer, Exception ex)123
{ 124
writer.AddAttribute(HtmlTextWriterAttribute.Title, BuildExceptionInfomation(ex));125
writer.AddStyleAttribute("font-weight", "700");126
writer.AddStyleAttribute("color", "#f00");127
writer.AddStyleAttribute("border", "1px solid #ddd");128
writer.AddStyleAttribute("cursor", "pointer");129
writer.AddStyleAttribute("padding", "0px 3px 0px 3px");130
writer.AddStyleAttribute("background-color", "#ffe");131
writer.RenderBeginTag(HtmlTextWriterTag.Span);132
writer.Write("!");133
writer.RenderEndTag();134
}135

136
/// <summary>137
/// 生成异常信息138
/// </summary>139
/// <param name="ex"></param>140
/// <returns></returns>141
private string BuildExceptionInfomation(Exception ex)142
{143
StringBuilder sb = new StringBuilder();144
sb.Append(ex.Message);145
sb.Append(Environment.NewLine);146
sb.Append(ex.GetType().FullName);147
sb.Append(Environment.NewLine);148
sb.Append(ex.StackTrace);149
return sb.ToString();150
}151
152
/// <summary>153
/// 中断程序的执行154
/// </summary>155
/// <param name="ex"></param>156
protected virtual void Interrupt(Exception ex)157
{158
throw new HttpUnhandledException(ex.Message, ex);159
}160
}161

上面的代码只重载了OnPreRender、Render和CreateChildControls三个方法,实际上还有OnInit、OnLoad等,可以视实际需要而重载,这样重载之后,所有错误都被捕捉,并存放在错误栈中,并在呈现时将错误以某种格式呈现在界面上。注意,继承AbstractControl基类的控件应重载如RenderByCatchedException之类的方法。
如果某些错误不希望被捕捉,而是直接抛出到页面上,这时候还可以调用Interrupt方法来将错误直接抛出到页面上,并中断整个页面的执行。


浙公网安备 33010602011771号