ASP.NET 頁面級錯誤事件(Page.Error)雖能集中處理異常,但一旦某控制項拋出異常,整頁面渲染中斷,導致其他正常控制項無法顯示。實務上常需「控制項級隔離」:單一控制項錯誤不影響頁面其餘部分。
AbstractControl封裝控制項生命週期關鍵方法(CreateChildControls、OnPreRender、Render),統一捕獲異常並存入堆疊,最後在 Render 階段以紅色驚嘆號標記並提示詳細錯誤資訊。
public abstract class AbstractControl : Control {
public Stack Exceptions { get; } = new Stack();
protected override void CreateChildControls() {
try { CreateChildControlsByCatchedException(); }
catch (HttpUnhandledException) { throw; }
catch (Exception ex) { Exceptions.Push(ex); }
}
protected virtual void CreateChildControlsByCatchedException() { }
protected override void OnPreRender(EventArgs e) {
try { OnPreRenderByCatchedException(e); }
catch (HttpUnhandledException) { throw; }
catch (Exception ex) { Exceptions.Push(ex); }
}
protected virtual void OnPreRenderByCatchedException(EventArgs e) { base.OnPreRender(e); }
protected override void Render(HtmlTextWriter writer) {
if (Exceptions.Count > 0) {
while (Exceptions.Count > 0)
RenderException(writer, (Exception)Exceptions.Pop());
return;
}
try { RenderByCatchedException(writer); }
catch (HttpUnhandledException) { throw; }
catch (Exception ex) { RenderException(writer, ex); }
}
protected virtual void RenderByCatchedException(HtmlTextWriter writer) { base.Render(writer); }
private void RenderException(HtmlTextWriter writer, Exception ex) {
writer.AddAttribute(HtmlTextWriterAttribute.Title, BuildExceptionInfomation(ex));
writer.AddStyleAttribute("font-weight", "700");
writer.AddStyleAttribute("color", "#f00");
writer.AddStyleAttribute("border", "1px solid #ddd");
writer.AddStyleAttribute("cursor", "pointer");
writer.AddStyleAttribute("padding", "0px 3px");
writer.AddStyleAttribute("background-color", "#ffe");
writer.RenderBeginTag(HtmlTextWriterTag.Span);
writer.Write("!");
writer.RenderEndTag();
}
private string BuildExceptionInfomation(Exception ex) {
var sb = new StringBuilder();
sb.AppendLine(ex.Message);
sb.AppendLine(ex.GetType().FullName);
sb.AppendLine(ex.StackTrace);
return sb.ToString();
}
protected virtual void Interrupt(Exception ex) {
throw new HttpUnhandledException(ex.Message, ex); // 需中斷整頁時呼叫
}
}
AbstractControl,覆寫 CreateChildControlsByCatchedException、OnPreRenderByCatchedException、RenderByCatchedException 撰寫業務邏輯。Interrupt(ex)。OnInit、OnLoad 等其他生命週期方法。此模式實現「控制項級錯誤隔離」,提升頁面容錯與使用者體驗。