我正在动态加载用户控件,将它们添加到 Web 表单的 Controls 集合中。
如果用户控件在渲染时导致未处理的异常,我想隐藏它们。
因此,我尝试连接到每个 UserControl 的 Error 事件,但似乎该事件永远不会像对 Page 类那样为 UserControls 触发。
做了一些谷歌搜索,它似乎并不乐观。这里有什么想法吗?
我正在动态加载用户控件,将它们添加到 Web 表单的 Controls 集合中。
如果用户控件在渲染时导致未处理的异常,我想隐藏它们。
因此,我尝试连接到每个 UserControl 的 Error 事件,但似乎该事件永远不会像对 Page 类那样为 UserControls 触发。
做了一些谷歌搜索,它似乎并不乐观。这里有什么想法吗?
不需要额外的逻辑!这就是重点,您对有问题的类什么都不做,只是将它们包装在一些实例化气泡包装中!:)
好的,我打算只是要点,但我想亲眼看看这个工作,所以我拼凑了一些非常粗略的代码,但这个概念就在那里,而且它似乎工作。
为长篇道歉
这基本上就是我提到的“气泡”。它将获取控件 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>");
}
}
}
享受!
这是一个有趣的问题.. 在自定义控件等方面我仍然很新鲜,但这是我的想法(请随意评论/纠正人!)..(我有点想/在这里大声写出来!)
只是我的想法,火焰消失!: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 子类来错误处理其渲染和加载方法(以便它们按您的意愿隐藏),然后为您的用户控件继承它?
我不确定我是否理解您的回复。您如何加载控件并将它们添加到控件集合中?
这就是“更新”部分中添加的部分的全部意义。您可以灵活地在任何地方使用SafeLoader。
我不知道为什么你觉得你没有对 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));
}
}