Welcome 微信登录

首页 / 网页编程 / ASP.NET / 探讨对Web控件的异常处理

探讨对Web控件的异常处理2012-01-10 博客园 简单生活在使用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  }1718  protected override void CreateChildControls()19  {20    try21    {22      CreateChildControlsByCatchedException();23    }24    catch (HttpUnhandledException)25    {26      throw;27    }28    catch (Exception ex)29    {30      Exceptions.Push(ex);31    }32  }3334  /**//// <summary>35  /// 创建子控件(已进行异常捕捉处理)36  /// </summary>37  protected virtual void CreateChildControlsByCatchedException()38  {39  }4041  /**//// <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  }6061  /**//// <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  }7778  /**//// <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  }107108  /**//// <summary>109  /// 呈现(已进行错误捕捉处理)110  /// </summary>111  /// <param name="writer"></param>112  protected virtual void RenderByCatchedException(HtmlTextWriter writer)113  {114    base.Render (writer);115  }116117  /**//// <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  }135136  /**//// <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方法来将错误直接抛出到页面上,并中断整个页面的执行。