Qualcuno può spiegare perché Server.Execute() richiede che i miei UserControls renderizzati contengano i tag <form>
(o, in alternativa, ciò che sto facendo erroneamente sta creando Server. Execute() richiede tag modulo nei miei UserControls)?Problemi di rendering di UserControl utilizzando Server.Execute() in un servizio Web ASMX
ho creato un servizio ASMX caricare dinamicamente controlli utente tramite JQuery + JSON come segue:
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);
}
}
io carico il controllo in una pagina tramite il seguente bit di JQuery che sostituisce un con ContentPlaceholder id con l'HTML restituito dal servizio:
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>
Questo funziona con un enorme avvertimento. Se non mi definisco un modulo all'interno markup del controllo .ascx poi HttpContext.Current.Server.Execute() genera un HttpException con il seguente messaggio:
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"/>
Quando ho aggiunto un tag form al controllo ascx per aggirare questo problema, il form dovrebbe eseguire il rendering, ma il renderer riscrive il tag form nel controllo in modo che rimandi al servizio ASMX anziché al modulo definito nella pagina aspx.
Ho cercato su google e ho scoperto l'ottimo esempio di Scott Guthrie ViewManager. Non vedo nulla di fondamentalmente diverso da ciò che ha fatto lì, il che mi porta a credere che quello che sto facendo dovrebbe funzionare.
Sono propenso ad accettare questa risposta, poiché suona vera, ma voglio provarla prima (che non sarà per alcuni giorni). –