2009-06-10 11 views
15

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.

risposta

21

Sembra che la risposta fu sepolto nei commenti per la ViewManager

Si vorrà una classe che eredita da pagina e sostituisce l'assegno di server non controlli in una forma

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

Poi, quando il rendering del controllo, utilizzare

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

sto assumendo si perde la possibilità di avere eventi che sparano da eventuali controlli resi in questo modo.

+0

Sono propenso ad accettare questa risposta, poiché suona vera, ma voglio provarla prima (che non sarà per alcuni giorni). –

0

si potrebbe cambiare il metodo di GetControl() come segue:

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

System.Web.UI.Page non ha execute() metodi, per quanto posso dire. Intendi 'page.Server.Execute (controlName, writer, false)'? –

+0

Siamo spiacenti. Ecco cosa intendevo. – ichiban

+0

Sfortunatamente, questo non funziona con UserControls (.ascx). page.Server.Execute() funziona solo per le pagine .aspx. –

1

Invece di usare un controllo nascosto asp.net sul controllo utente, basta usare un normale input nascosto HTML con i tag del codice <%%> a inserisci i dati in questo modo:

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

"testo" è una variabile pubblica nel codice dietro il file.

Questo ha funzionato per me e non ha richiesto un modulo con runat="server".

+0

In questo caso, la tua idea non funzionerà. Il mio esempio invoca il servizio Web dal browser e sostituisce il campo nascosto con il contenuto restituito, in Javascript, sul client. <% %> viene elaborato sul server. –

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 

si aggiunge il modulo dinamicamente

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 

Si aggiunge il modulo dinamicamente

Problemi correlati