捕获ASP.NET UserControls中未处理的异常
我正在动态加载用户控件,将它们添加到Web窗体的Controls集合中。
我想隐藏用户控件,如果它们在渲染时导致未处理的异常。
因此,我尝试挂钩到每个UserControl的Error事件,但似乎该事件从未像对Page类一样对UserControls触发。
进行了一些谷歌搜索,似乎没有希望。这里有什么想法吗?
解决方案
回答
Global.asax和Application_Error?
http://www.15seconds.com/issue/030102.htm
或者仅单个页面上的Page_Error事件:
http://support.microsoft.com/kb/306355
void Page_Load(object sender, System.EventArgs e) { throw(new ArgumentNullException()); } public void Page_Error(object sender,EventArgs e) { Exception objErr = Server.GetLastError().GetBaseException(); string err = "<b>Error Caught in Page_Error event</b><hr><br>" + "<br><b>Error in: </b>" + Request.Url.ToString() + "<br><b>Error Message: </b>" + objErr.Message.ToString()+ "<br><b>Stack Trace:</b><br>" + objErr.StackTrace.ToString(); Response.Write(err.ToString()); Server.ClearError(); }
另外,Karl Seguin(嗨,Karl!)发表了一篇关于使用HttpHandler的文章:
http://codebetter.com/blogs/karlseguin/archive/2006/06/12/146356.aspx
(不确定是否有复制权限,但是如果我们想写一个答案,我们会得到我的支持吗?)
回答
如何添加一个新的UserControl子类,该子类将错误处理其渲染和加载方法(以便它们按意愿隐藏),然后从中继承用户控件?
回答
这是一个有趣的问题。.关于自定义控件等,我还是很新鲜,但是这是我的想法(可以随意评论/纠正人们!)(我有点想/在这里写下来!)
- 如果在渲染过程中发生错误,在某些情况下,为时不晚吗? (因为某些控件HTML可能已经发送到Writer并输出了)。
- 因此,最好不要包装用户控件的Render方法,而是将其传递给自己,而不是将其传递给"实时" HtmlTextWriter引用,而是传递自己的方法,捕获所有在此小安全性"气泡"中引发的异常(如果一切顺利) ,然后将结果HTML传递给实际的HtmlTextWriter?
- 该逻辑可能会滞留于通用包装类,我们可以使用该包装类在运行时动态加载/呈现控件。
- 如果确实发生任何错误,我们将拥有所需的所有信息! (即控件参考等)。
只是我的想法,火焰消失了! :D;)
回答
根据发生错误的位置,我们可以执行以下操作:
public abstract class SilentErrorControl : UserControl { protected override void Render( HtmlTextWriter writer ) { //call the base's render method, but with a try catch try { base.Render( writer ); } catch ( Exception ex ) { /*do nothing*/ } } }
然后继承SilentErrorControl而不是UserControl。
回答
mmilic,接下来是我们对我以前的想法的回应。
无需其他逻辑!重点是,我们对所涉及的类不执行任何操作,只需将它们包装在一些实例化泡沫包装中即可! :)
好的,我只是想提出要点,但我想亲自看看这项工作,因此我将一些非常粗糙的代码拼凑在一起,但是这个概念确实存在并且似乎可行。
漫长的道歉
安全加载器
基本上,这就是我提到的"气泡"。它将获取控件HTML,捕获在渲染过程中发生的任何错误。
public class SafeLoader { public static string LoadControl(Control ctl) { // In terms of what we could do here, its down // to you, I will just return some basic HTML saying // I screwed up. try { // Get the Controls HTML (which may throw) // And store it in our own writer away from the // actual Live page. StringWriter writer = new StringWriter(); HtmlTextWriter htmlWriter = new HtmlTextWriter(writer); ctl.RenderControl(htmlWriter); return writer.GetStringBuilder().ToString(); } catch (Exception) { string ctlType = ctl.GetType().Name; return "<span style=\"color: red; font-weight:bold; font-size: smaller;\">" + "Rob + Controls = FAIL (" + ctlType + " rendering failed) Sad face :(</span>"; } } }
和一些控件
好的,我只是在这里嘲笑了两个控件,一个控件将抛出另一个控件将导致垃圾。指向这里,我不要胡扯。这些将替换为自定义控件。
不良控制
public class BadControl : WebControl { protected override void Render(HtmlTextWriter writer) { throw new ApplicationException("Rob can't program controls"); } }
良好控制
public class GoodControl : WebControl { protected override void Render(HtmlTextWriter writer) { writer.Write("<b>Holy crap this control works</b>"); } }
这一页
OK,让我们看一下"测试"页面。在这里,我只是实例化控件,获取它们的html并输出它,然后我将介绍有关设计人员支持的想法。
页面代码隐藏
protected void Page_Load(object sender, EventArgs e) { // Create some controls (BadControl will throw) string goodHtml = SafeLoader.LoadControl(new BadControl()); Response.Write(goodHtml); string badHtml = SafeLoader.LoadControl(new GoodControl()); Response.Write(badHtml); }
思想
好吧,我知道我们在想什么,"这些控件以编程方式实例化,那么对设计人员的支持又如何?我花了很多时间才使这些控件对设计人员变得很好,现在我们正在弄乱我的mojo"。
好的,所以我还没有真正测试过它(可能会在一分钟内完成!),但是这里的想法是覆盖页面的CreateChildControls方法,并获取表单上添加的每个控件的实例,并通过SafeLoader运行它。如果代码通过,则可以按常规将其添加到Controls集合中;如果没有通过,则可以创建错误的文字或者其他内容,由我的朋友决定。
最后..
再次,对冗长的帖子表示抱歉,但我想在此处获取代码,以便我们进行讨论:)
我希望这有助于证明我的想法:)
更新
通过将控件插入设计器中并使用此方法覆盖CreateChildControls方法进行测试,效果很好,可能需要进行一些清理才能使外观看起来更好,但我将留给我们;
protected override void CreateChildControls() { // Pass each control through the Loader to check // its not lame foreach (Control ctl in Controls) { string s = SafeLoader.LoadControl(ctl); // If its bad, smack it downnnn! if (s == string.Empty) { ctl.Visible = false; // Prevent Rendering string ctlType = ctl.GetType().Name; Response.Write("<b>Problem Occurred Rendering " + ctlType + " '" + ctl.ID + "'.</b>"); } } }
享受!
回答
我不确定我是否理解答复。我们如何加载控件并将其添加到控件集合中?
这就是在"更新"部分中添加的全部内容。.我们可以随时随地灵活使用SafeLoader。
我不确定为什么我们会感觉没有对HTML的访问/控制权? SafeLoader的目标是我们不必关心html是什么,我们只需尝试并"输出"控件(在"气泡"内)并确定它在当前状态下是否可以加载。
如果确实如此(即返回了html),那么我们可以使用它来做自己喜欢的事情,输出html,然后将控件添加到控件集合中,无论如何!
如果不是,那么再次,我们可以执行我们喜欢的操作,呈现错误消息,引发自定义异常。
我希望这可以澄清问题,如果没有,请大声喊叫:)