捕获ASP.NET UserControls中未处理的异常

时间:2020-03-05 18:39:34  来源:igfitidea点击:

我正在动态加载用户控件,将它们添加到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,然后将控件添加到控件集合中,无论如何!

如果不是,那么再次,我们可以执行我们喜欢的操作,呈现错误消息,引发自定义异常。

我希望这可以澄清问题,如果没有,请大声喊叫:)