【问题标题】:Catching unhandled exceptions in ASP.NET UserControls在 ASP.NET 用户控件中捕获未处理的异常
【发布时间】:2010-09-05 20:44:12
【问题描述】:

我正在动态加载用户控件,并将它们添加到 Web 表单的 Controls 集合中。

如果用户控件在渲染时导致未处理的异常,我想隐藏它们。

所以,我尝试连接到每个 UserControl 的 Error 事件,但似乎该事件永远不会像对 Page 类那样为 UserControls 触发。

在谷歌上搜索了一下,似乎没有希望。这里有什么想法吗?

【问题讨论】:

    标签: asp.net exception user-controls


    【解决方案1】:

    mmilic,从your response 到我的previous idea..

    不需要额外的逻辑!这就是重点,您对有问题的类什么都不做,只是将它们包装在一些实例化气泡包装中! :)

    好的,我打算只说要点,但我想亲眼看看这项工作,所以我拼凑了一些非常粗略的代码,但概念就在那里,而且似乎有效。 p>

    为长篇道歉

    安全加载器

    这基本上就是我提到的“气泡”。它将获取控件 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>");
        }
    }
    

    页面

    好的,让我们看一下“测试”页面。这里我只是简单地实例化控件,获取它们的 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);
        }
    

    想法

    好的,我知道你在想什么,“这些控件是以编程方式实例化的,设计师支持呢?我花了好几个小时让这些控件对设计师来说很好,现在你在搞砸我的魔力”。

    好的,所以我还没有真正测试过这个(可能会在几分钟内完成!)但是这里的想法是覆盖页面的 CreateChildControls 方法,并获取添加到表单上的每个控件的实例并运行它安全加载器。如果代码通过了,你可以像往常一样将它添加到 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>");
            }
        }
    }
    

    享受吧!

    【讨论】:

      【解决方案2】:

      这是一个有趣的问题。在自定义控件等方面我仍然很新鲜,但这是我的想法(请随意评论/纠正人!)..(我有点想/在这里大声写出来!)

      • 如果在渲染过程中出现错误,在某些情况下,会不会太晚了? (因为某些控件 HTML 可能已经发送到 Writer 并输出)。
      • 因此,最好包装用户控件的 Render 方法,而不是将其传递给“Live”HtmlTextWriter 的引用,而是传递自己的,捕获在这个小安全“气泡”中引发的任何异常,如果一切顺利,然后将生成的 HTML 传递给实际的 HtmlTextWriter?
      • 这个逻辑可能会被挂在一个通用包装类中,您可以使用它在运行时动态加载/呈现控件。..
      • 如果确实发生任何错误,您可以使用所有需要的信息! (即控制引用等)。

      只是我的想法,燃烧吧! :D ;)

      【讨论】:

        【解决方案3】:

        根据您的错误发生的位置,您可以执行类似...

        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。

        【讨论】:

          【解决方案4】:

          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

          (不确定复制它的权限,但如果你想写一个答案,你得到了我的支持☺)

          【讨论】:

            【解决方案5】:

            添加一个新的 UserControl 子类如何处理其渲染和加载方法的错误(以便它们按您的意愿隐藏),然后为您的用户控件继承该子类?

            【讨论】:

              【解决方案6】:

              我不确定我是否理解 your response.. 您如何加载控件并将它们添加到控件集合中?

              这就是“更新”部分中添加的部分的重点。您可以灵活地在任何地方使用 SafeLoader

              我不知道您为什么觉得您无法访问/控制 Html? SafeLoader 的目标是您不关心 html 是什么,您只需尝试“输出”控件(在“气泡”内)并确定它在当前状态下是否可以正常加载。

              如果确实如此(即返回 html),那么您可以用它做您喜欢的事情,输出 html,将控件添加到控件集合中,等等!

              如果没有,那么你可以做你喜欢的事,呈现错误消息,抛出自定义异常。选择是你的!

              我希望这有助于为您澄清事情,如果没有,请大声疾呼:)

              【讨论】:

                【解决方案7】:

                我使用了@Keith 的方法,但问题是在抛出异常之前一直呈现控件,这可能会导致打开的 HTML 标记。如果处于调试模式,我还会在控件中呈现异常信息。

                  protected override void Render(System.Web.UI.HtmlTextWriter writer)
                  {
                     try
                     {
                        // Render the module to a local a temporary writer so that if an Exception occurs
                        // the control is not halfway rendered - "it is all or nothing" proposition
                        System.IO.StringWriter sw = new System.IO.StringWriter();
                        System.Web.UI.HtmlTextWriter htw = new System.Web.UI.HtmlTextWriter(sw);
                        base.Render(htw);
                
                        // We made it!  Copy the Control Render over
                        writer.Write(sw.GetStringBuilder().ToString());
                     }
                     catch (System.Exception ex)
                     {
                        string message = string.Format("Error Rendering Control {0}\n", ID);
                        Log.Error(message, ex);
                        if (Page.IsDebug)
                           writer.Write(string.Format("{0}<br>Exception:<br><pre>{1}\n{2}</pre>", message, ex.Message, ex.StackTrace));
                     }
                  }
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2017-11-25
                  • 2013-04-08
                  • 2012-02-03
                  • 1970-01-01
                  • 2011-02-13
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多