2010年8月12日 星期四

使用 Ajax 方式取得 UserControl 的內容

同事問到,如何以 Ajax 的方式取得 UserControl 的內容。

問題

由於 UserControl 是無法單獨被客戶端所呼叫(Request),因此我們必須想個辦法將 UserControl 加到一個 Page內。

解決步驟

1 Web Service 回傳 UserControl 的內容

使用 Visual Studio (我使用 2010) 建立一個 Web Application,並加入一個 WebService。程式碼如下

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class WebService1 : System.Web.Services.WebService
{
    [WebMethod(EnableSession = true)]
    public string GetUserControlHtml(string location)
    {
        var webServiceString = string.Format("Thread Id={0}, Time={1}", Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("HHmmss fffffff"));
        var page = new Page();
        var userControl = (UserControl)page.LoadControl(location);
        userControl.EnableViewState = false;
        var form = new HtmlForm();
        form.Controls.Add(userControl);
        page.Controls.Add(form);
        var writer = new StringWriter();
        HttpContext.Current.Server.Execute(page, writer, false);

        return webServiceString + "<br /> " + RemoveFormTagFromHtml(writer.ToString());
    }


    /// <summary>
    /// 移掉 Form Tag
    /// </summary>
    /// <param name="html"></param>
    /// <returns></returns>
    private static string RemoveFormTagFromHtml(string html)
    {
        return Regex.Replace(html, @"<[/]?(form)[^>]*?>", "", RegexOptions.IgnoreCase);
    }
}

過程大略是:手動建立一個 Page,Page 內加入一個 Form,Form 動態載入指定的 UserControl。使用 Server.Execute 取得 html 內容後,將 <form tag 移除,避免避免原 asp.net 網頁失敗。

2 寫 UserControl

今天的配角是 UserControl。UserControl並不難實作。我簡單的寫了兩個 UserControl,分別 Thread.Sleep 了2秒,3秒。

3 於呼叫網頁使用 Ajax 方式呼叫 ASP.NET Web Service

我再入成兩種方式來呼叫。一個是 ASP.NET AJAX,一個則是 jQuery。

3.1 使用 ASP.NET AJAX 呼叫 Web Service

加入一個 ScriptManager,並加入一個 ScriptReference 參考到剛剛建立的 WebService。利用動態產生的 javascript file (可使用 http://…/WebService1.asmx/jsdebug 取得內容)協助呼叫 ASP.NET Web Service

3.2 使用jQuery 的 .ajax 呼叫 Web Service

使用jQuery 大概是近來 Web 技術的顯學吧。為了方便未來的 ASP.NET MVC的使用,還是乖乖的學一下吧。

<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true"
    CodeBehind="Default.aspx.cs" Inherits="WebApplication3._Default" %>

<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
    <script src="Scripts/jquery-1.4.1.js" type="text/javascript"></script>
    <script type="text/javascript">
        $(document).ready(function () {
            var datestring = getNow();
            $("#div1").html("at client, " + datestring + "<br/>");
            getData("WebUserControl1.ascx", $("#div1"));

            datestring = getNow();
            $("#div2").html("at client, " + datestring + "<br/>");
            getDataByJquery("WebUserControl2.ascx", $("#div2"));
        });

        function getNow() {
            var today = new Date();
            return today.format("HHmmss ffffff");
        }
        function getData(controlLocation, container) {
            WebApplication3.WebService1.GetUserControlHtml(controlLocation,
                function (result) {
                    $(container).append(result);
                },
                function () { alert(error.get_message()); }
            );
        }

        function getDataByJquery(controlLocation, container) {
            var datestring = getNow();
            $.ajax({
                type: "POST",
                contentType: "application/json; charset=utf-8",
                url: "WebService1.asmx/GetUserControlHtml",
                data: "{'location': '" + controlLocation + "'}",
                dataType: "json",
                success: function (result) {
                    $(container).append(result.d);
                },
                error: function (error) { alert(error.responseText); }
            });
        }
    </script>
</asp:Content>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
    <asp:ScriptManager ID="ScriptManager1" runat="server">
        <Services>
            <asp:ServiceReference Path="~/WebService1.asmx" />
        </Services>
    </asp:ScriptManager>
    <h2>
        Welcome to ASP.NET!
    </h2>
    <div style="border: 2px solid red">
        <h1>
            User Controll 1</h1>
        <div id="div1">
        </div>
    </div>
    <div style="border: 2px solid red">
        <h1>
            User Controll 2</h1>
        <div id="div2">
        </div>
    </div>
    <div id="result">
    </div>
</asp:Content>

4 測試

測試時發現狀況還不錯。雖然同時發出 Request, 約2秒後得到UserControl1 的內容,但 UserControl2卻在約略在 5.5 秒後才得到內容,而非3秒。為什麼?

image

5 Session 造成 lock,因而 Delay

原來是步驟1中,[WebMethod(EnableSession = true)] 這個 true 所造成的。改成 EnableSessioin = false後,網頁測試結果如下

image
這樣就符合我們的期待了。

沒事最好還是不要用 Session。

範例下載

沒有留言:

Share with Facebook