在ASMX web服务中使用Server.Execute()发出呈现用户控件

时间:2022-05-21 15:47:41

Can anyone explain to why Server.Execute() is requiring my rendered UserControls to contain <form> tags (or alternately, what I am doing wrong that is making Server.Execute() require form tags in my UserControls)?

谁能解释为什么Server.Execute()要求我的呈现的UserControls包含

标记(或者,我做错了什么,使Server.Execute()在我的UserControls中要求form标记)?

I have created an ASMX service to dynamically load UserControls via JQuery+JSON as follows:

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

ControlService.asmx

ControlService.asmx

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

ControlService.cs

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

I load the control into a page via the following bit of JQuery which replaces a with the id ContentPlaceholder with the HTML returned from the service:

我通过以下JQuery将控件加载到一个页面,该页面用id ContentPlaceholder替换为从服务返回的HTML:

JQueryControlLoadExample.aspx

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>

This works with one huge caveat. If I don't define a form inside the .ascx control's markup then HttpContext.Current.Server.Execute() throws an HttpException with the following message:

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

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

必须将“HiddenField”类型的“hdnspecialoffer”控件放在带有runat=server的表单标记中。

SimpleControl.ascx

SimpleControl.ascx

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

When I added a form tag to the ascx control to work around this, the form would render, but the renderer rewrites the form tag in the control so that it POSTs back to the ASMX service instead of the form defined in the aspx page.

当我向ascx控件添加一个表单标记来处理这个问题时,表单将呈现出来,但是渲染器会重写控件中的表单标记,以便它将返回给ASMX服务,而不是在aspx页面中定义的表单。

I googled around and discovered Scott Guthrie's excellent ViewManager example. I don't see anything fundamentally different from what he did there, which leads me to believe that what I am doing ought to work.

我搜索了一下,发现了Scott Guthrie的优秀的ViewManager示例。我没有看到任何与他在那里所做的根本不同的东西,这让我相信我所做的应该是有用的。

5 个解决方案

#1


21  

Looks like the answer was buried in the comments for the ViewManager

看起来答案隐藏在ViewManager的注释中

You'll want a class that inherits from Page and overrides the check for server controls not in a form

您将需要一个类,它继承自Page并覆盖表单之外的对服务器控件的检查

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

Then when you render the control, use

然后在呈现控件时使用

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

I'm assuming you'll lose the ability to have events firing from any controls rendered this way.

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

#2


1  

Instead of using an asp.net hidden control on your user control, just use a regular html hidden input with the code tags <% %> to fill the data like this:

不用在用户控件上使用asp.net隐藏控件,只需使用一个常规的html隐藏输入,代码标签<% >填充如下数据:

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

"text" is a public variable in the code behind file.

“文本”是文件背后的公共变量。

This worked for me and didn't require a form with runat="server".

这对我很有效,并且不需要使用runat=“服务器”的表单。

#3


0  

You could change your GetControl() method as follows:

您可以更改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();
}

#4


0  

    <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

You add the Form dinamically

用dinamically添加表单

#5


0  

<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

You add the Form dinamically

用dinamically添加表单

#1


21  

Looks like the answer was buried in the comments for the ViewManager

看起来答案隐藏在ViewManager的注释中

You'll want a class that inherits from Page and overrides the check for server controls not in a form

您将需要一个类,它继承自Page并覆盖表单之外的对服务器控件的检查

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

Then when you render the control, use

然后在呈现控件时使用

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

I'm assuming you'll lose the ability to have events firing from any controls rendered this way.

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

#2


1  

Instead of using an asp.net hidden control on your user control, just use a regular html hidden input with the code tags <% %> to fill the data like this:

不用在用户控件上使用asp.net隐藏控件,只需使用一个常规的html隐藏输入,代码标签<% >填充如下数据:

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

"text" is a public variable in the code behind file.

“文本”是文件背后的公共变量。

This worked for me and didn't require a form with runat="server".

这对我很有效,并且不需要使用runat=“服务器”的表单。

#3


0  

You could change your GetControl() method as follows:

您可以更改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();
}

#4


0  

    <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

You add the Form dinamically

用dinamically添加表单

#5


0  

<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

You add the Form dinamically

用dinamically添加表单