Проблемы с предоставлением UserControl с использованием Server.Execute() в веб-службе ASMX
Может ли кто-нибудь объяснить, почему серверу .Execute() требуется, чтобы мои обработанные UserControls содержали теги <form>
(или, напротив, то, что я делаю неправильно, что делает Server.Execute(), требует тегов формы в моем UserControls)?
Я создал службу ASMX для динамической загрузки UserControls через JQuery + JSON следующим образом:
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, который заменяет идентификатор ContentPlaceholder кодом 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, чтобы обойти это, форма будет отображать, но рендерер перезаписывает тег формы в элементе управления, чтобы он возвращал POST обратно в службу ASMX вместо формы, определенной в aspx стр.
Я нашел googled и открыл Скотта Гатри отличный ViewManager. Я не вижу ничего принципиально отличного от того, что он там делал, что заставляет меня поверить, что то, что я делаю, должно работать.
Ответы
Ответ 1
Похож, что ответ был похоронен в комментариях для ViewManager
Вам понадобится класс, наследующий от страницы, и переопределяет проверку для элементов управления сервером не в форме
public class FormlessPage : Page
{
public override void VerifyRenderingInServerForm(Control control)
{
}
}
Затем, когда вы визуализируете элемент управления, используйте
Page page = new FormlessPage();
UserControl ctl = (UserControl)page.LoadControl(controlName);
//etc
Я предполагаю, что вы потеряете возможность запускать события из любых элементов управления, обработанных таким образом.
Ответ 2
Вместо использования скрытого элемента управления asp.net в вашем пользовательском элементе управления просто используйте обычный скрытый ввод html с тегами кода <%% > , чтобы заполнить такие данные:
<input id="Hidden1" type="hidden" value="<%= text %>"/>
"текст" - это общедоступная переменная в файле, находящемся за кодом.
Это сработало для меня и не требовало формы с runat="server"
.
Ответ 3
Вы можете изменить свой метод 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
<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
Вы добавляете форму динамически
Ответ 5
<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
Вы добавляете форму динамически