【问题标题】:Issues rendering UserControl using Server.Execute() in an ASMX web service在 ASMX Web 服务中使用 Server.Execute() 呈现 UserControl 时出现问题
【发布时间】:2010-11-01 20:51:20
【问题描述】:

谁能解释为什么 Server.Execute() 要求我渲染的 UserControls 包含 <form> 标签(或者,我做错了什么,使 Server.Execute() 在我的 UserControls 中需要表单标签)?

我已经创建了一个 ASMX 服务来通过 JQuery+JSON 动态加载 UserControls,如下所示:

ControlService.asmx

<%@ WebService Language="C#" CodeBehind="ControlService.asmx.cs" Class="ManagementConcepts.WebServices.ControlService" %>

ControlService.cs

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class ControlService : System.Web.Services.WebService
{
    private string GetControl(String controlName, String ClassId)
    {
        Page page = new Page();
        UserControl ctl = (UserControl)page.LoadControl(controlName);

        page.Controls.Add(ctl);
        StringWriter writer = new StringWriter();
        HttpContext.Current.Server.Execute(page, writer, false);
        return writer.ToString();
    }
    [WebMethod]
    [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
    public string GetSimpleControl(string ClassId)
    {
        return GetControl("SimpleControl.ascx", ClassId);
    }
}

我通过以下 JQuery 将控件加载到页面中,该 JQuery 将带有 ID ContentPlaceholder 的 a 替换为从服务返回的 HTML:

JQueryControlLoadExample.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="JQueryControlLoadExample.aspx.cs" Inherits="ControlService_Prototype._Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>ControlService Prototype</title>
</head>
<body>
    <form id="theForm" runat="server" action="JQueryControlLoadExample.aspx">
        <asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="true" >
            <Scripts>
                <asp:ScriptReference NotifyScriptLoaded="true" Path="~/Scripts/jquery-1.3.2.js" />
            </Scripts>
        </asp:ScriptManager>
        <div>
        <asp:HiddenField runat="server" ID="hdncourse"/>
        <asp:HiddenField runat="server" ID="hdnTargetContent" Value="GetSimpleControl"/>
        <div runat="server" id="ContentPlaceholder" class="loading"></div>
        </div>
        <script type="text/javascript">
            $(document).ready(function() {
                var servicemethod = document.getElementById("hdnTargetContent").value;
                $.ajax({
                type: "POST",
                    url: "ControlService.asmx/" + servicemethod,
                    data: "{'ClassId':'"+document.getElementById("hdncourse").value+"'}",
                    contentType: "application/json; charset=utf-8",
                    dataType: "json",
                    success: function(msg) {
                        $('#ContentPlaceholder').html(msg.d);
                    }
                });
            });
        </script>
    </form>
</body>
</html>

这有一个很大的警告。如果我没有在 .ascx 控件的标记中定义表单,那么 HttpContext.Current.Server.Execute() 会抛出带有以下消息的 HttpException:

Control 'hdnspecialoffer' of type 'HiddenField' must be placed inside a form tag with runat=server.

SimpleControl.ascx

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="SimpleControl.ascx.cs" Inherits="ControlService_Prototype.UserControls.SimpleControl" %>
    <asp:HiddenField runat="server" ID="hdnspecialoffer"/>

当我向 ascx 控件添加一个表单标签来解决这个问题时,表单会呈现,但呈现器会重写控件中的表单标签,以便它返回到 ASMX 服务,而不是在 aspx 中定义的表单页面。

我搜索了一下,发现了 Scott Guthrie 的出色 ViewManager 示例。我看不出任何与他在那里所做的根本不同的事情,这让我相信我所做的应该是有效的。

【问题讨论】:

    标签: c# asp.net user-controls asmx


    【解决方案1】:
    <System.Web.Services.WebMethod()> _
    Public Shared Function GetDetails(ByVal filename As String) As String
        Dim page As Page = New Page()
        Dim ctl As recDetails = CType(page.LoadControl("~/Controles/recDetails.ascx"), recDetails)
        ctl.FileName = filename
    
        page.EnableEventValidation = False
        Dim _form As New HtmlForm()
        page.Controls.Add(_form)
        _form.Controls.Add(ctl)
    
        Dim writer As New System.IO.StringWriter()
        HttpContext.Current.Server.Execute(page, writer, False)
        Dim output As String = writer.ToString()
        writer.Close()
        Return output
    End Function
    

    动态添加表单

    【讨论】:

      【解决方案2】:
          <System.Web.Services.WebMethod()> _
      Public Shared Function GetDetails(ByVal filename As String) As String
          Dim page As Page = New Page()
          Dim ctl As recDetails = CType(page.LoadControl("~/Controles/recDetails.ascx"), recDetails)
          ctl.FileName = filename
      
          page.EnableEventValidation = False
          Dim _form As New HtmlForm()
          page.Controls.Add(_form)
          _form.Controls.Add(ctl)
      
          Dim writer As New System.IO.StringWriter()
          HttpContext.Current.Server.Execute(page, writer, False)
          Dim output As String = writer.ToString()
          writer.Close()
          Return output
      End Function
      

      动态添加表单

      【讨论】:

        【解决方案3】:

        看起来答案隐藏在 ViewManager 的 cmets 中

        您需要一个从 Page 继承并覆盖对不在表单中的服务器控件的检查的类

        public class FormlessPage : Page
        {
            public override void VerifyRenderingInServerForm(Control control)
            {
            }
        }
        

        然后在渲染控件时,使用

        Page page = new FormlessPage();
        UserControl ctl = (UserControl)page.LoadControl(controlName);
        //etc
        

        我假设您将失去从任何以这种方式呈现的控件触发事件的能力。

        【讨论】:

        • 我倾向于接受这个答案,因为它听起来是对的,但我想先尝试一下(这不会是几天)。
        【解决方案4】:

        不要在用户控件上使用 asp.net 隐藏控件,只需使用带有代码标签 的常规 html 隐藏输入来填充数据,如下所示:

        <input id="Hidden1"  type="hidden" value="<%= text %>"/>
        

        “文本”是代码隐藏文件中的公共变量。

        这对我有用,不需要runat="server" 的表格。

        【讨论】:

        • 你的想法在这种情况下是行不通的。我的示例从浏览器调用 Web 服务,并在客户端用返回的 Javascript 内容替换隐藏字段。 在服务器上处理。
        【解决方案5】:

        您可以按如下方式更改您的 GetControl() 方法:

        private string GetControl(String controlName, String ClassId)
        {
            Page page = new Page();
            StringWriter writer = new StringWriter();
            page.Server.Execute(controlName, writer, false);
            return writer.ToString();
        }
        

        【讨论】:

        • System.Web.UI.Page 据我所知没有任何 Execute() 方法。你的意思是page.Server.Execute(controlName, writer, false)
        • 不幸的是,这不适用于 UserControls (.ascx)。 page.Server.Execute() 仅适用于 .aspx 页面。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-02-14
        • 1970-01-01
        • 2022-09-25
        • 1970-01-01
        • 1970-01-01
        • 2011-03-05
        • 1970-01-01
        相关资源
        最近更新 更多