2009-06-10 73 views
15

任何人都可以解釋爲什麼Server.Execute()要求我的呈現UserControls包含<form>標記(或者,我做錯了什麼是製作服務器。 Execute()在我的UserControl中需要表單標籤)?使用Server.Execute()在ASMX Web服務中呈現UserControl的問題

我已經如下創建一個ASMX服務通過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的下面一頁的頁面,該頁面用從服務返回的HTML替換id爲ContentPlaceholder:

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頁面中定義的表單。

我搜索了一下,發現了Scott Guthrie的優秀ViewManager例子。我沒有看到任何與他在那裏完全不同的東西,這導致我相信我正在做的事情應該工作。

回答

21

貌似答案被埋葬在爲ViewManager

你會想從頁面繼承並重寫爲服務器旁邊的一類意見控件並不是以

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

然後當你渲染控件,使用

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

我假設你將失去使用這種方式渲染任何控件的事件。

0

你可以改變你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(); 
} 
+0

System.Web.UI.Page沒有任何執行()方法,只要我可以告訴。 你的意思是`page.Server.Execute(controlName,writer,false)`? – 2009-06-10 18:49:00

+0

對不起。我正是這個意思。 – ichiban 2009-06-10 18:51:34

+0

不幸的是,這對於UserControls(.ascx)不起作用。 page.Server.Execute()僅適用於.aspx頁面。 – 2009-06-10 19:19:51

1

改爲讓用戶控制使用asp.net隱藏控件,只需使用普通的HTML隱藏輸入的代碼標籤<%%>來填入這樣的數據:

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

「text」是代碼隱藏文件中的公共變量。

這適用於我,並不需要與runat="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 

可以在添加表單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 

可以在添加表單dinamically