【问题标题】:Asp.net error creating usercontrol from WebMethod从 WebMethod 创建用户控件的 Asp.net 错误
【发布时间】:2009-06-16 12:23:45
【问题描述】:

我引用的是article reference

动态创建 UserControl 并通过 jQuery 将其传回页面。

当我只是在 UserControl“Hello World”中做一个简单的文本时,一切都很好......但是,当我尝试在控件上放置交互式控件时,我在我的 WebMethod 中收到以下消息(所以 jQuery 调用的东西是不相关)(进一步的测试表明,文本框和按钮会导致问题,而不是标签)

执行处理程序“System.Web.UI.Page”的子请求时出错

这是网络方法:

[WebMethod]
public static string GetCtrl(string cname)
{
    StringWriter sw = new StringWriter();

    Page p = new Page();
    Control c = p.LoadControl("~/Controls/" + cname);
    p.Controls.Add(c);

    try
    {
        HttpContext.Current.Server.Execute(p, sw, false);
    }
    catch (Exception err)
    {
        return err.Message;
    }
    sw.Close();

    return sw.ToString();
}

异常发生在 Server.Execute 调用期间。

可能无法解决,我只是想知道为什么交互式控件会导致这种情况。

编辑: 接受下面的建议,我更深入地研究并发现内部异常表明它必须位于标有 runat="server" 的表单标记内,而我在表单标记内的 aspx 页面上显示此控件...我的猜测是,那里必须有某种“asp.net 魔术”连接才能使控件运行...无论如何,无论如何,知道如何呈现带有控件的页面会很好(即使它在这种情况下无法使用)

所以我查看了上面代码的输出,对于那些好奇的人:

<span id="ctl00_lbl1">abc: </span>

所以控件在页面上正确渲染(只有标签id ='lbl1'),但是,控件本身是渲染的,页面内容根本不存在......有没有办法生成页面源也是? (我一定不明白 Server.Execute 函数的工作方式)

【问题讨论】:

  • 根据一个建议,我更深入地检查了调试信息,发现了以下内部异常: 内部异常如下(比我之前的稍微有用):Control 'ctl00_btn1' 'Button' 类型的必须放在带有 runat=server 的表单标签内。因为这是在 Page 对象上呈现的...我想知道是否需要做一些“准备工作”才能使该页面成为正确的 aspx 页面?...因为我基本上是在动态构建它(我们甚至不会谈论将整个内容嵌入另一个页面的不当性)

标签: asp.net user-controls


【解决方案1】:

我将从缩小问题范围开始。例如,如果你离开会发生什么

p.Controls.Add(c);

如果你正确地实现using 语句会发生什么?

using (StringWriter sw = new StringWriter()) {
    // ...
    HttpContext.Current.Server.Execute(p, sw, false);
    return sw.ToString();
}

如果你放弃 try/catch 会发生什么?除了 Message 属性之外,它会花费您在异常中的所有信息,那么为什么不直接关闭它呢?在任何情况下,你的调用者都可能期待 HTML,所以如果你保留它,你可能(稍后)想要包装输出:

return "<p>" + ex.ToString() + "</p>";

一点一点,删除东西,直到问题消失。


根据您从 InnerException 中了解到的情况,我建议您将 HtmlForm 控件添加到页面,然后将加载的控件添加为 HtmlForm 的子控件。

【讨论】:

  • using 语句无济于事,因为它只会让我对清理有一点控制,并且在我什至考虑清理任何东西之前,Server.Execute 函数中发生了异常(经过测试只是为了确保)放入了 try/catch,这样我就可以获得消息的实时反馈,而不仅仅是一个空白屏幕,并给我一个进行调试中断的好地方。 (深入了解我的调试信息很有帮助)
  • 我认为,如果没有 try/catch,ASP.NET Health Monitoring 会记录整个异常,包括您发现有用的 InnerException。正确实现异常和 using 语句很有帮助,因为它可以让像我这样的人专注于真正的问题,而不是浪费时间对良好实践进行迂腐。
【解决方案2】:

Using Scott Gu's blog as a reference,我也遇到了在我的小部件中加载服务器控件的相同问题(例如 GridView 和 RadTreeView 控件会导致相同的错误),用于我们公司的仪表板。按照 John Saunders 的提示,我添加了一个 HTML 表单控件和脚本管理器控件(用于 RadTreeView 控件)并解决了问题。现在我的用户控件呈现为纯 HTML。 w00t!

[WebMethod]
public static string[] LoadWidget(string widgetID, string widgetPath)
{
    try
    {
        var pageHolder = new Page();
        var form = new HtmlForm();
        var viewControl = (UserControl)pageHolder.LoadControl(widgetPath);
        var scriptManager = new ScriptManager();
        form.Controls.Add(scriptManager);
        form.Controls.Add(viewControl);
        pageHolder.Controls.Add(form);

        var output = new StringWriter();
        HttpContext.Current.Server.Execute(pageHolder, output, false);

        return new string[]
        {
            widgetID, output.ToString()
        };
    }
    catch (Exception e)
    {
        // handle error...
    }
}

【讨论】:

    【解决方案3】:

    我会尝试渲染控件并将该字符串发回...

    Control ctrl;
    StringBuilder sb = new StringBuilder();
    StringWriter tw = new StringWriter(sb);
    HtmlTextWriter hw = new HtmlTextWriter(tw);
    
    ctrl.RenderControl(hw);
    return sb.ToString();
    

    【讨论】:

    • @George,考虑到您正在创建的大多数对象都实现了 IDisposable,您还会实现 using 语句吗?
    • 使用 RenderControl 方法是个好主意,不幸的是,这不会导致控件经历页面生命周期(因此不会调用 Page_Load 事件)
    • 控件有它自己的生命周期。如果您在 Page 中有代码,则该对象包含在将其移动到 Load 事件中。 msdn.microsoft.com/en-us/library/aa719775(VS.71).aspx
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多