探讨对Web控件的异常处理

在使用ASP.NET时,常常使用Page的错误事件Error进行错误捕捉和处理。这种方式可以集中处理所有异常,这种方式有利有弊。集中处理的好处就不用啰嗦了,这里只说明一下这种方式的局限,就是当页面中的某个控件发生异常之后,整个页面执行都会中断,然后处理异常,这样一来,页面就无法显示。

在实际开发中,常常有这样的需求,即页面是由多个相对独立的控件组成,其中一个控件的错误不能影响到其它控件的正常显示。这就需要在控件内部捕捉错误,并自行处理错误,然而控件基类并没有提供这样的错误捕捉功能。如何用简单有效方法来实现呢?

其实我们可以实现一个基类,并把所有在控件生命期中会调用到的方法都封装起来,这样只要继承这个控件,就可以方便地实现在控件内部自行捕捉错误的功能。请看下面的代码:

 

  1public 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

上面的代码只重载了OnPreRender、Render和CreateChildControls三个方法,实际上还有OnInit、OnLoad等,可以视实际需要而重载,这样重载之后,所有错误都被捕捉,并存放在错误栈中,并在呈现时将错误以某种格式呈现在界面上。注意,继承AbstractControl基类的控件应重载如RenderByCatchedException之类的方法。

如果某些错误不希望被捕捉,而是直接抛出到页面上,这时候还可以调用Interrupt方法来将错误直接抛出到页面上,并中断整个页面的执行。

posted on 2006-08-19 18:45  良村  阅读(2056)  评论(2编辑  收藏  举报

导航