2009-06-10 5 views
15

Quelqu'un peut-il expliquer pourquoi Server.Execute() exige que mes UserControls rendus contiennent des balises <form> (ou bien, ce que je fais de mal à faire le serveur. Execute() nécessite des balises de formulaire dans mes UserControls)?Problèmes de rendu UserControl à l'aide de Server.Execute() dans un service Web ASMX

j'ai créé un service ASMX pour charger dynamiquement UserControls via JQuery + JSON comme suit:

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

je charge le contrôle en une page via le bit suivant de JQuery qui remplace a avec l'id ContentPlaceholder par le code HTML renvoyé par le service:

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> 

Cela fonctionne avec une mise en garde énorme. Si je ne définit pas une forme à l'intérieur du balisage de contrôle .ascx puis HttpContext.Current.Server.Execute() renvoie une HttpException avec le message suivant:

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"/> 

Lorsque j'ajoutais une balise de formulaire au contrôle ascx pour contourner ce problème, le formulaire restituait, mais le rendu réécritait la balise de formulaire dans le contrôle afin qu'il renvoie au service ASMX au lieu du formulaire défini dans la page ASPX.

J'ai fait un tour d'adresse et découvert l'excellent exemple ViewManager de Scott Guthrie. Je ne vois rien de fondamentalement différent de ce qu'il a fait là-bas, ce qui me porte à croire que ce que je fais doit fonctionner.

Répondre

21

On dirait que la réponse a été enterré dans les commentaires pour le ViewManager

Vous voulez une classe qui hérite de la page et remplace le contrôle pour les contrôles serveur pas sous une forme

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

Puis, quand vous rendre le contrôle, utilisez

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

Je suppose que vous perdrez la possibilité d'organiser des événements de tir de tous les contrôles rendus de cette façon.

+0

Je penche pour accepter cette réponse, car elle sonne vrai, mais je veux l'essayer d'abord (ce qui ne sera pas pour quelques jours). –

0

Vous pouvez changer votre méthode GetControl() comme suit:

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 n'a pas de méthodes Execute() pour autant que je peux dire. Voulez-vous dire 'page.Server.Execute (controlName, writer, false)'? –

+0

Désolé. c'est ce que je voulais dire. – ichiban

+0

Malheureusement, cela ne fonctionne pas pour UserControls (.ascx). page.Server.Execute() ne fonctionne que pour les pages .aspx. –

1

Au lieu d'utiliser un asp.net contrôle caché sur votre contrôle utilisateur, il suffit d'utiliser un html régulièrement entrée cachée avec les balises de code <%%> à remplissez les données comme ceci:

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

"text" est une variable publique dans le code derrière le fichier.

Cela a fonctionné pour moi et n'a pas besoin d'un formulaire avec runat="server".

+0

Votre idée ne fonctionnera pas dans ce cas. Mon exemple appelle le service Web depuis le navigateur et remplace le champ masqué par le contenu renvoyé, en Javascript, sur le client. <% %> est traitée sur le serveur. –

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 

Vous ajoutez le formulaire dinamically

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 

Vous ajoutez le formulaire dinamically