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

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

因此,我尝试挂钩每个 UserControl 的 Error 事件,但似乎 UserControl 永远不会像 Page 类那样触发该事件。

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

有帮助吗?

解决方案

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>");
    }
}

这一页

好的,让我们看看“测试”页面..在这里,我简单地实例化控件,抓取它们的 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 方法,并获取表单上添加的每个控件的实例并通过 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>");
        }
    }
}

享受!

其他提示

这是一个有趣的问题..当谈到自定义控件等时,我仍然很新鲜,但这是我的想法(请随意评论/纠正人们!)..(我在这里大声思考/写作!)

  • 如果在渲染过程中出现错误,在某些情况下,是不是就太晚了?(因为某些控件 HTML 可能已经发送到 Writer 并输出)。
  • 因此,最好包装用户控件的 Render 方法,而不是向其传递对“Live”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。

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?SafeLoader 的目标是您不 关心 html 是什么,您只需尝试“输出”控件(在“气泡”内)并确定它在当前状态下是否加载正常。

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

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

我希望这有助于您澄清问题,如果没有,请大喊:)

我使用了 @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));
     }
  }
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top