代码之家  ›  专栏  ›  技术社区  ›  Jeff Leonard

在ASMX web服务中使用Server.Execute()呈现UserControl时出现问题

  •  15
  • Jeff Leonard  · 技术社区  · 17 年前

    有人能解释为什么Server.Execute()要求呈现的UserControl包含 <form> 标记(或者,我做错了什么,使Server.Execute()在我的UserControls中需要表单标记)?

    我创建了一个ASMX服务,通过JQuery+JSON动态加载用户控件,如下所示:

    <%@ 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替换为服务返回的HTML:

    <%@ 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页面中定义的表单。

    我在谷歌上搜索了一下,发现斯科特·古思里的 ViewManager

    5 回复  |  直到 17 年前
        1
  •  21
  •   Bela    17 年前

    看来答案就藏在了对 ViewManager

    您将需要一个从页继承并重写非表单中的服务器控件检查的类

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

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

        2
  •  1
  •   orandov    17 年前

    不要在用户控件上使用asp.net隐藏控件,只需使用带有代码标记的常规html隐藏输入<%%&燃气轮机;要像这样填充数据:

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

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

    runat="server" .

        3
  •  1
  •   Jfsanchez2k Jfsanchez2k    16 年前
    <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
    

    您可以通过友好方式添加表单

        4
  •  0
  •   ichiban    17 年前

    你可以改变你的想法 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();
    }
    
        5
  •  0
  •   Javier Sanchez    16 年前
        <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