2.7 ASP.NET AJAX Hello World 樣本程式
Hello World 已經成為所有語言教科書中的必備樣本程式,本書也不能免於俗套。在本章的最後,
我們還是通過一個最簡單的ASP.NET AJAX Hello World 應用程式來邁出這勇敢的第一步。
2.7.1 樣本程式介紹
該程式的介面上有一個文字框和一個按鈕,2-16 所示。使用者在文字框中輸入自己的名字之
後點擊這個按鈕,ASP.NET AJAX 將非同步呼叫位於伺服器端的一個Web Service 。在得到一個問
候字串後,將其顯示在頁面中,2-17 所示。需要注意的是,顯示問候字串時頁面並不
是完全重新載入,而只是進行局部更新,避免了瀏覽器重繪時的閃爍,也就是所謂的“Ajax” 方
式。
圖2-16 ASP.NET AJAX Hello World 程式介面
圖2-17 伺服器發給Dflying 的問候
2.7.2 設計頁面的HTML 部分
要實現這個簡單的Hello World 程式,首先建立一個ASP.NET AJAX Web Site ,並在其中建立名
為ASPNETAJAXHelloWorld.aspx 的ASP.NET 頁面。在該頁面中,添加如下的HTML 標籤:
<label for="tbName">Your Name:</label><input id="tbName" type="text" />
<input id="btnSayHello" type="button" value="Say Hello From Server!" />
<div id="lbMessage"></div>
可以看到,其中定義了一個作為文字框顯示的<input>,id 為tbName,用來讓使用者輸入名字;一
個id 為btnSayHello 的作為按鈕顯示的<input>,用來觸發對伺服器的非同步呼叫;一個空的<div>,
id 為lbMessage ,伺服器端返回的結果將顯示在這裡。
頁面中包含了一些簡單的CSS ,代碼如下:
*
{
font-family: Tahoma;
font-size: 0.96em;
}
input
{
border: 1px solid #000;
}
這樣,本程式中所有的介面部分元素就完成了。運行一下,應該可以看到2-16 所示的介面。
自然,此時該程式尚不能完成任何功能。
2.7.3 編寫提供服務的Web Service
然後編寫伺服器端的Web Service 。在本ASP.NET AJAX Web Site 中建立一個Web Service ,命名
為HelloWorldService.asmx 。在其中聲明一個Web Method ,該Web Service 的代碼如下,注意其
中粗體部分:
using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
[WebService(Namespace = "http://www.dflying.net/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService()]
public class HelloWorldService : System.Web.Services.WebService
{
[WebMethod]
public string GetHelloWorldString(string name)
{
return string.Format("Welcome to ASP.NET AJAX world, {0}!. Now it is {1}.",
name,DateTime.Now);
}
}
可以看到,我們為該Web Service 類應用了[System.Web.Script.Services.ScriptService()] 屬性,這
個屬性是讓ASP.NET AJAX 能夠從用戶端訪問到該Web Service 所必需的。該Web Method 的名
稱為GetHelloWorldString() ,它接受一個string 作為參數並將同樣返回一個string 。其實現非常
簡單,即構造並返回一個包含使用者輸入的名字和當前伺服器的時間的字串。
編輯完成該Web Service 之後,我們可以先在瀏覽器中運行並測試一下——在開發過程中隨時對
現有代碼進行階段性測試是一個非常好的習慣,有助於儘早發現潛在的錯誤。若一切順利,你
將看到2-18 所示的Web Service 測試頁面。
圖2-18 Web Service 測試頁面
點擊GetHelloWorldString 連結,導航至GetHelloWorldString() 方法的測試頁面,並輸入一個使用者
名(見圖2-19)。
點擊Invoke 按鈕,一切順利的話,你將看到2-20 所示的GetHelloWorldString() 方法的返回
值(其中時間部分可能有所不同)。
圖2-19 GetHelloWorldString() 方法的測試頁面
圖2-20 調用GetHelloWorldString() 方法
這樣,伺服器端的準備即宣告完成。接下來讓我們產生並在頁面中引用這個Web Method 的客
戶端代理,以便於稍後在用戶端JavaScript 中對其進行調用。
2.7.4 使用ScriptManager 控制項在頁面上添加Web Service 的用戶端引用
切換回ASPNETAJAXHelloWorld.aspx 頁面的設計器,從Toolbox 中拖入一個ASP.NET AJAX
ScriptManager 控制項。這時ASPNETAJAXHelloWorld.aspx 頁面的設計器應該2-21 所示。
ScriptManager 控制項是ASP.NET AJAX 的核心,用來將ASP.NET AJAX 架構所需要的JavaScript
檔案、自訂的ASP.NET AJAX 用戶端組件以及該頁面將要調用的Web Service 的用戶端代理
發送到用戶端。關於ScriptManager 控制項,將在第3 章中詳細介紹。
圖2-21 添加了ScriptManager 控制項的ASP.NET 頁面
因為這個程式中將用到前面建立的檔案名稱為HelloWorldService.asmx 的Web Service ,所以我們
需要在ScriptManager 控制項中添加其引用,這樣ScriptManager 控制項才可以自動產生它的用戶端
JavaScript 代理並發送至瀏覽器。
選中ScriptManager 控制項,然後在Properties 工具視窗中點擊Services 右面的按鈕,2-22 所
示。
圖2-22 Properties 工具視窗中的ScriptManager 控制項
在彈出的對話方塊中點擊Add 按鈕添加一個新的Service ,並指定其Path 為HelloWorldService.
asmx ,添加後的介面將2-23 所示。
圖2-23 為ScriptManager 控制項添加Service 引用
點擊OK 按鈕之後,HelloWorldService.asmx 的引用就被添加到了ScriptManager 中。由於程式
中還需要使用一些定義在“Futures”指令碼中的用戶端控制項,所以接下來我們還要在ScriptManager
中添加相應的“Futures”指令碼引用。
選中ScriptManager 控制項,然後在Properties 工具視窗中點擊Scripts 右面的按鈕,將彈出
ScriptReference Collection Editor 對話方塊。點擊Add 按鈕添加一個新的Script,並指定其Assembly
為Microsoft.Web.Preview ,Name 為PreviewScript.js ,這樣做即表示我們要把內嵌在
Microsoft.Web.Preview.dll 程式集中的名為PreviewScript.js 的指令碼資源引入到頁面中。添加後的
介面將2-24 所示。
圖2-24 為ScriptManager 控制項添加Script 引用
點擊OK 按鈕之後,這個“Futures” 指令碼的引用就被添加到了ScriptManager 中。這時若切換至頁
面的源檔案視圖,可以看到Visual Studio 自動為我們產生了如下ScriptManager 控制項的代碼:
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Scripts>
<asp:ScriptReference Name="PreviewScript.js"
Assembly="Microsoft.Web.Preview" />
</Scripts>
<Services>
<asp:ServiceReference Path="HelloWorldService.asmx" />
</Services>
</asp:ScriptManager>
2.7.5 用JavaScript 讓程式運轉起來
最後一步,讓用戶端以非同步方式直接調用該Web Service 中的GetHelloWorldString() 方法以取
得用戶端所需的資料。用ASP.NET AJAX XML 指令碼的方式可能較難理解,所以在這個樣本程式
中我們選擇用JavaScript 的方式。
首先,在頁面的<head> 標籤中插入一個<script> 標籤,並在其中定義三個控制項,分別代表讓使用者
輸入名字的文字框、用來觸發對伺服器進行請求的按鈕以及用來顯示伺服器端返回結果的標籤:
var g_tbName = null;
var g_btnSayHello = null;
var g_lbMessage = null;
然後定義一個pageLoad() 方法。類似於ASP.NET 中伺服器端的Page_Load() 方法,該pageLoad()
方法將在ASP.NET AJAX 用戶端架構初始化之後自動被調用,程式可以在其中進行一些必要的
初始化操作。這裡我們在該方法中初始化上面的三個ASP.NET AJAX 用戶端控制項:
function pageLoad()
{
g_tbName = new Sys.Preview.UI.TextBox($get('tbName'));
g_tbName.initialize();
g_btnSayHello = new Sys.Preview.UI.Button($get('btnSayHello'));
g_btnSayHello.add_click(getServerHelloString);
g_btnSayHello.initialize();
g_lbMessage = new Sys.Preview.UI.Label($get('lbMessage'));
g_lbMessage.initialize();
}
在pageLoad() 方法的第一行,我們看到了一個奇怪的函數——$get() 。該函數是ASP.NET AJAX
提供的對JavaScript 函數document.getElementById() 的簡寫形式,用來通過DOM 元素的id 來找
到這個DOM 元素。然後,將這個DOM 元素的引用傳遞給Sys.Preview.UI.TextBox,即ASP.NET
AJAX 用戶端TextBox 控制項的建構函式,表示該TextBox 控制項將作為這個DOM 元素在ASP.NET
AJAX 用戶端架構中的封裝。也就是說,這個TextBox 控制項實際上以物件導向的方法封裝了真
正的DOM 元素的各種屬性/操作。最後,將返回的用戶端TextBox 控制項的引用儲存在tbName
中。關於ASP.NET AJAX 的用戶端控制項,將在第Ⅱ卷中詳細介紹。
第二行中調用了該TextBox 控制項的initialize() 方法,對其進行了初始化。
對於按鈕和顯示返回結果的標籤,我們也採用了同樣的方式進行初始化。但是需要注意的是下
面這一句:
g_btnSayHello.add_click(getServerHelloString);
該句代碼為g_btnSayHello 按鈕的click 事件添加了一個事件處理函數,名為getServer-
HelloString() 。getServerHelloString() 事件處理函數的代碼如下:
function getServerHelloString()
{
HelloWorldService.GetHelloWorldString(g_tbName.get_text(), cb_getServerHello
String);
}
這個函數中只有一條語句,就是調用HelloWorldService.asmx 檔案中GetHelloWorldString() 方法
的用戶端代理。可以看到調用該方法的格式為[類名].[ 方法名],很讓人興奮,不是嗎?居然如此
簡單直觀,和我們熟悉的C#代碼結構完全一樣!完全不用像第1 章中樣本程式那樣要書寫那麼
多的代碼。
我們為該方法傳入了兩個參數:第一個是使用者在文字框中的名字字串,通過g_tbName.get_text()
得到,當它到達伺服器端時,ASP.NET AJAX 會自動將其轉化為.NET 架構中的String 對象;第
二個是該非同步呼叫完成時的回呼函數,我們將其指定為cb_getServerHelloString() 。關於ASP.NET
AJAX 中調用Web Service 的詳細方法,將在第Ⅱ卷中詳細介紹。
讓我們再看一下cb_getServerHelloString() 回呼函數的代碼:
function cb_getServerHelloString(result)
{
g_lbMessage.set_text(result);
}
該函數同樣非常簡單明了。注意到該函數接受一個名為result 的參數,這是ASP.NET AJAX 框
架自動提供的,其中包含了這次非同步呼叫的傳回值。在本樣本程式中,result 參數也就是
HelloWorldService.asmx 檔案中GetHelloWorldString() 方法的傳回值。在傳回值發送至用戶端之
後,ASP.NET AJAX 用戶端架構同樣將把它轉換為JavaScript 中的字串對象。然後在該函數中,
我們調用g_lbMessage.set_text(result) 方法,將伺服器端返回的字串設定給了g_lbMessage 並顯
示出來。
ajaxHelloworld.aspx
//c# code
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="ajaxHelloworld.aspx.cs" Inherits="ajaxHelloworld" %>
<%@ Register Assembly="System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
Namespace="System.Web.UI" TagPrefix="asp" %>
<!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>ajaxHelloworld</title>
<style type="text/css">
*
{
font-family: Tahoma;
font-size: 0.96em;
}
input
{
border: 1px solid #000;
}
</style>
<script type="text/javascript">
var g_tbName = null;
var g_btnSayHello = null;
var g_lbMessage = null;
function pageLoad()
{
g_tbName = new Sys.Preview.UI.TextBox($get('tbName'));
g_tbName.initialize();
g_btnSayHello = new Sys.Preview.UI.Button($get('btnSayHello'));
g_btnSayHello.add_click(getServerHelloString);
g_btnSayHello.initialize();
g_lbMessage = new Sys.Preview.UI.Label($get('lbMessage'));
g_lbMessage.initialize();
}
function getServerHelloString()
{
HelloworldService.GetHelloWorldString(g_tbName.get_text(), cb_getServerHelloString);
}
function cb_getServerHelloString(result)
{
g_lbMessage.set_text(result);
}
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
<label for="tbName">
<asp:ScriptManager id="ScriptManager1" runat="server">
<services>
<asp:ServiceReference Path="HelloworldService.asmx"></asp:ServiceReference>
</services>
<Scripts>
<asp:ScriptReference Assembly="Microsoft.Web.Preview" Name="PreviewScript.js" />
</Scripts>
</asp:ScriptManager><br />
Your Name:</label><input id="tbName" type="text" />
<input id="btnSayHello" type="button" value="Say Hello From Server!" />
<div id="lbMessage"></div>
</div>
</form>
</body>
</html>
HelloworldService.cs
//C# code
using System;
using System.Web;
using System.Collections;
using System.Web.Services;
using System.Web.Services.Protocols;
/// <summary>
/// HelloworldService 的摘要說明
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService()]
public class HelloworldService : System.Web.Services.WebService {
public HelloworldService () {
//如果使用設計的組件,請取消注釋以下行
//InitializeComponent();
}
[WebMethod]
public string GetHelloWorldString(string name)
{
return string.Format("Welcome to ASP.NET AJAX world, {0}!. Now it is {1}.",
name, DateTime.Now);
}
}
web.config
<system.web>
<httpHandlers>
<remove verb="*" path="*.asmx"/>
<add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory,System.Web.Extensions,Version=1.0.61025.0,Culture=neutral,PublicKeyToken=31bf3856ad364e35"/>
<add verb="*" path="*_AppService.axd" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory,System.Web.Extensions,Version=1.0.61025.0,Culture=neutral,PublicKeyToken=31bf3856ad364e35"/>
<add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler,System.Web.Extensions,Version=1.0.61025.0,Culture=neutral,PublicKeyToken=31bf3856ad364e35" validate="false"/>
</httpHandlers >
</system.web>