使用ASP.NET AJAX非同步呼叫Web Service和頁面中的類方法(1):調用Web Service、調用頁面中的類方法

來源:互聯網
上載者:User

本文來自《ASP.NET AJAX程式設計 第II卷:用戶端Microsoft AJAX Library相關》的第三章《非同步呼叫Web Service和頁面中的類方法》,請同時參考本章的其他文章。

3.1 調用Web Service

之所以ASP.NET AJAX將Web Service提高到了如此的重要位置上,讓它幾乎成為了ASP.NET AJAX伺服器端邏輯最受推薦的實現方式,是因為Web Service天生就是純粹為了商務邏輯而設計的。我們都知道,Web Service沒有提供什麼“花哨”的使用者介面,而是心無旁騖地專註於程式邏輯上的實現,這恰好和ASP.NET AJAX用戶端編程模型所倡導的“將表現層和商務邏輯層徹底分開”的理念不謀而合——用戶端的ASP.NET AJAX架構用來處理常式所有的介面、與使用者互動功能,伺服器端則僅僅提供純粹的資料,不涉及任何錶現樣式。

藉助於ASP.NET AJAX非同步通訊層所自動產生的Web Service用戶端訪問代理,在表現層代碼,也就是JavaScript中調用Web Service擷取資料成為了一件異常簡單的事情——其表現出的優雅甚至讓我們不敢相信:難道Ajax程式也能寫得這麼簡單?

接下來就讓我們通過一個簡單的樣本程式瞭解一下在ASP.NET AJAX應用程式中使用JavaScript非同步呼叫Web Service的方法。出於示範的目的,程式的功能非常簡單:使用者在頁面的文字框中輸入名字,然後點擊旁邊的按鈕,3-1所示。

圖3-1 使用者在介面中輸入自己的名字

程式將藉助ASP.NET AJAX非同步通訊層以Ajax方式把使用者的名字發送至伺服器端的Web Service。隨後該Web Service在伺服器端根據使用者的名字產生一段問候資訊並發送回用戶端,用戶端收到伺服器響應之後,將把這段問候資訊顯示出來,3-2所示。

圖3-2 程式顯示出來自伺服器的問候資訊

讓我們先從伺服器端的Web Service入手。建立一個名為SimpleWebService的Web Service類並在其中聲明一個普通的Web Service方法——SayHello()。該方法將接受一個名為name的參數,並產生一條問候資訊返回:

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class SimpleWebService : System.Web.Services.WebService
{
    [WebMethod]
    public string SayHello(string name)
    {
        return string.Format("Hello {0}!", name);
    }
}

這就是個普通的Web Service,沒有任何不一樣之處。注意不要忘記為SayHello()方法添加[WebMethod]屬性,這是每個Web方法都必需的。

為了讓ASP.NET AJAX產生該Web Service的用戶端非同步呼叫代理,進而允許我們在JavaScript代碼中直接調用該方法,我們還要再為SimpleWebService類添加[ScriptService]屬性,這一部分才是ASP.NET AJAX為Web Service提供的附加功能(注意代碼中粗體部分):

//…………
[ScriptService]
//…………
public class SimpleWebService : System.Web.Services.WebService
{
    //…………
}

提示:我們也可以直接為需要暴露給用戶端的Web Service方法添加[ScriptService]屬性,而不必將其添加到Web Service類上。

[ScriptService]屬性位於System.Web.Script.Services命名空間中,如果需要的話,還要添加如下的using語句:

using System.Web.Script.Services;

下面列出完整的SimpleWebService Web Service代碼如下,注意其中粗體部分:

using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Web.Script.Services;
 
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService]
public class SimpleWebService : System.Web.Services.WebService
{
    [WebMethod]
    public string SayHello(string name)
    {
        return string.Format("Hello {0}!", name);
    }
}

完成了Web Service編寫之後,我們來先行測試一下——開發過程中不斷地進行階段性測試有助於儘快發現潛在的問題,並將其扼殺在萌芽中。如果一切順利的話,那麼測試該Web Service時可以看到3-3所示的結果。

圖3-3 測試Web Service時的介面

接下來即可用ASP.NET AJAX非同步呼叫這個Web Service了。首先建立一個ASP.NET頁面。當然,該頁面所在的Web網站必須已經配置好了ASP.NET AJAX的支援,詳細配置方法請參考本書第I卷。在該頁面上添加一個ScriptManager伺服器端控制項,這是每一個ASP.NET AJAX應用程式都必不可少的:

<asp:ScriptManager ID="sm" runat="server">
</asp:ScriptManager>

為了讓ASP.NET AJAX為前面的Web Service產生用戶端非同步呼叫代理,我們需要在ScriptManager控制項中添加該Web Service的引用:

<asp:ScriptManager ID="sm" runat="server">
    <Services>
        <asp:ServiceReference Path="Services/SimpleWebService.asmx" />
    </Services>
</asp:ScriptManager>

這種聲明文法隱約中傳遞了這樣的含義:Web Service的用戶端非同步呼叫代理指令碼將由ScriptManager控制項管理——這非常自然,不是嗎?ScriptManager就是用來管理(manage)指令碼(script)的呀!關於<Services />標籤以及<asp:ServiceReference />標籤的詳細使用方法,在本書第I卷中已經有詳細討論,這裡不贅。

隨後聲明程式介面中必不可少的UI元素:

<input id="tbName" type="text" />
<input id="btnInvoke" type="button" value="Say Hello" 
    onclick="return btnInvoke_onclick()" />
<div id="result"></div>

其中id為tbName的<input />作為文字框,用來讓使用者輸入名字;id為btnInvoke的<input />作為按鈕,點擊將觸發非同步呼叫Web Service;id為result的<div />則用來將Web Service返回的問候內容顯示出來。這些id均將在稍後用到。

上面代碼中btnInvoke按鈕定義了click事件的事件處理函數,該函數的實現如下。注意這是用戶端JavaScript代碼:

function btnInvoke_onclick() {
    var theName = $get("tbName").value;
    SimpleWebService.SayHello(theName, onSayHelloSucceeded);
}

首先用$get("tbName").value取得了使用者在文字框中輸入的文字。然後第二句SimpleWebService.SayHello()即調用了ASP.NET AJAX非同步通訊層自動為SimpleWebService產生的用戶端代理。這是本樣本程式中最為重要的一句——與用C#在Web Service中聲明的SayHello()方法簽名相比,其參數個數以及順序均完全一樣,甚至調用文法也沒什麼特別——都是[NameSpace].[ClassName].[MethodName](param1, param2 …, callbackFunction)。由此我們能夠看出ASP.NET AJAX非同步通訊層為降低開發人員學習曲線、提高開發人員生產效率所做出的努力及良苦用心。

參考:關於用來取得DOM元素引用的$get()方法,請參考本卷第1章中的介紹。

不過用戶端代理還提供了額外的一個參數——非同步呼叫的回呼函數名稱,這裡為onSayHelloSucceeded。該回呼函數將在伺服器端非同步呼叫成功返回後由ASP.NET AJAX非同步通訊層自動調用。onSayHelloSucceeded()回呼函數的代碼如下:

function onSayHelloSucceeded(result) {
    $get("result").innerHTML = result;
}

onSayHelloSucceeded()回呼函數的result參數代表了本次非同步呼叫的返回結果,即Web Service方法的傳回值,這裡即為包含了使用者名稱字的問候語。該回呼函數將由ASP.NET AJAX非同步通訊層自動調用,其result參數也會由ASP.NET AJAX非同步通訊層傳遞進來,無需我們任何手工控制。在本樣本程式的onSayHelloSucceeded()回呼函數中,我們只是簡單地將這句問候語顯示在id為result的<div />中。

參考:ASP.NET AJAX非同步通訊層為Web Service自動產生的用戶端代理以及相應的回呼函數還提供了更多的參數和配置功能,這些都將在本章中詳細介紹。

這樣就完成了本樣本程式的所有代碼編寫。運行該程式,如果一切順利的話,你將看到3-1和圖3-2所示的介面。

ASP.NET AJAX的非同步通訊層在本樣本程式中小試牛刀,縱觀整個樣本程式的實現代碼,我們不難看出該架構的強大功能以及為我們開發人員細心周全的考慮。雖然在實際開發中,我們很難遇到本樣本程式中這樣簡單的功能。但麻雀雖小,五髒俱全,理解了這樣一個簡單的樣本程式之後,我們完全可以舉一反三,根據開發過程中的實際需要編寫不同的Web Service以及用戶端調用代碼,輕鬆地完成工作。

總結:想要使用ASP.NET AJAX在用戶端JavaScript中非同步呼叫伺服器端Web Service,我們需要:

  1. 為Web Service類或需要暴露給用戶端的Web Service方法添加[ScriptService]屬性;
  2. 為Web Service中需要暴露給用戶端的方法添加[WebMethod]屬性;
  3. 在頁面中的ScriptManager控制項中添加對該Web Service的引用;
  4. 在用戶端使用如下JavaScript文法調用該Web Service:
    [NameSpace].[ClassName].[MethodName](param1, param2 ......, callbackFunction)
  5. 為用戶端非同步呼叫指定回呼函數,在回呼函數中接收傳回值並進一步處理。

 

3.2 調用頁面中的類方法

讓用戶端JavaScript直接能夠非同步呼叫到伺服器端的Web Service,這看起來真的是個不錯的主意——理想化的分層Ajax應用程式就應該這樣嘛!不過作為被ASP.NET伺服器端開發模型“寵壞”了的我們,更加熟悉的方法是直接將方法寫在ASP.NET頁面中,比如處理頁面中的某個伺服器端按鈕Click事件的代碼,就可能這樣調用定義在同一張頁面代碼檔案中的方法:

protected void Button1_Click(object sender, EventArgs e)
{
    myLabel.Text = this.GetTextForLabel();
}
 
public string GetTextForLabel()
{
    // ......
    return "Some Text";
}

對於那些“遺留”的ASP.NET應用程式來講,這樣直接定義在ASP.NET頁面中的方法更是相當常見。若是僅僅為了配合ASP.NET AJAX的用戶端訪問Web Service功能,就將這些方法一一遷移到Web Service中,豈不是非常麻煩?

好在ASP.NET AJAX在設計時考慮到了這個問題,並提供給我們一種作為替代的選擇。ASP.NET AJAX非同步通訊層能夠將聲明在ASP.NET頁面中的公有的類方法(C#中的static,VB.NET中的Shared)當作Web Service中聲明的方法一樣對待,為其產生類似的用戶端調用代理。

我們還是通過一個執行個體程式來瞭解這個功能。該樣本程式的功能與介面均與前面一節中的完全一致,唯一的不同就是,用戶端非同步呼叫的不再是某個Web Service,而是定義在ASP.NET頁面中的類方法。

首先是定義在ASP.NET頁面中的類方法,完整的方法聲明如下:

[WebMethod]
public static string SayHelloFromPage(string name)
{
    return string.Format("Hello {0}!", name);
}

特別需要注意的是,若要讓ASP.NET AJAX為其產生用戶端調用代理,那麼一定要為該方法添加[WebMethod]屬性。

然後是ScriptManager控制項,注意粗體部分代碼設定了EnablePageMethods屬性為true,這也是讓用戶端能夠直接調用伺服器端頁面方法所必需的。若你忘記了設定該屬性,那麼程式將無法完成預期功能:

<asp:ScriptManager ID="sm" EnablePageMethods="true" runat="server" />

程式介面中的UI元素和前一個節中的樣本程式完全一致,這裡不贅:

<input id="tbName" type="text" />
<input id="btnInvoke" type="button" value="Say Hello" 
    onclick="return btnInvoke_onclick()" />
<div id="result"></div>

而本樣本程式中按鈕的click事件處理函數以及非同步呼叫的回呼函數則需要一定的修改,如下所示:

function btnInvoke_onclick() {
    var theName = $get("tbName").value;
    PageMethods.SayHelloFromPage(theName, onSayHelloSucceeded);
}
 
function onSayHelloSucceeded(result) {
    $get("result").innerHTML = result;
}

注意上述代碼中的粗體部分。可以看到,調用頁面方法代理時統一的首碼為PageMethods。接下來是頁面方法的名稱,這裡為SayHelloFromPage(),其參數列表和C#中方法的定義一致,額外的一個參數表示本次非同步呼叫的回呼函數。即文法為:

PageMethods.[MethodName](param1, param2 …, callbackFunction);

這樣即完成了本樣本程式,運行一下,我們將會看到3-1和圖3-2一樣的介面。

總結:想要使用ASP.NET AJAX在用戶端JavaScript中非同步呼叫定義在ASP.NET頁面中的方法,我們需要:

  1. 將該方法聲明為公有(public);
  2. 將該方法聲明為類方法(C#中的static,VB.NET中的Shared),而不是執行個體方法;
  3. 為該方法添加[WebMethod]屬性;
  4. 將頁面中ScriptManager控制項的EnablePageMethods屬性設定為true;
  5. 在用戶端使用如下JavaScript文法調用該頁面方法:
    PageMethods.[MethodName](param1, param2 …, callbackFunction);
  6. 為用戶端非同步呼叫指定回呼函數,在回呼函數中接收傳回值並進一步處理。
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.