AJAX模型基於兩個層次--客戶端應用程序層和服務器應用程序層。在這種模型下,客戶端層向服務器層發送請求,而服務器層向客戶端層返迴響應。服務器端點通過URL標識,並通過源(feed)(通常為JSON[JavaScript Object Notation]數據流)向客戶端暴露數據。服務器層只是一個接收調用並將其轉發給應用程序業務邏輯層的外觀。下圖描繪了整個模型:
為使ASP.NET AJAX頁面能夠調用遠程服務,該服務必須滿足幾點要求,其中最關鍵的一點與端點和底層平台的位置有關。支持AJAX的服務必須位於調用者所處的域中。這意味著該服務必須是ASP.NET XML Web服務(.asmx端點),必須以ASP.NET應用程序的形式寄放於同一Web服務器的某個IIS應用程序中。
總的來說,對於ASP.NET AJAX應用服務,有3種定義服務器層服務的方式:
1. 帶有asmx端點的ASP.NET XML Web服務。
2. 帶有svc端點的WCF服務。
3. 帶有aspx端點的頁面方法,這些方法定義在與主調頁面相同的頁面中。
“服務(Service)”這個詞往往被誤用。在AJAX中,服務指的是隸屬於應用程序的代碼(位於應用程序的域中),用於向客戶端暴露相應的功能。從根本上講,AJAX應用程序使用的服務一般不通過簡單對象訪問協議(SOAP)進行通信(而是使用JSON),不必是面向服務架構(SOA)中自治的服務。它們與自身所處平台和域綁定。因此,不能稱這裡的服務為WS-*Web服務和SOA服務。
REST服務
針對AJAX應用程序的服務圍繞著暴露給Web客戶端數據和資源。二者可通過HTTP獲取,要求客戶端通過URL(也可以有HTTP標頭)來訪問數據和命令操作。客戶端與服務的交互是通過GET、POST、PUT和DELETE這樣的動作來完成。換言之,URL用於描述所要獲取的資源,HTTP動作用於描述對資源執行的操作。這類交互過程中交換的數據由簡單的格式表示,甚至可以用聯合格式(如RSS和ATOM)表示。
具有這些特性的服務為具象狀態傳輸(Representational State Transfer,REST)。
數據的序列化
AJAX調用包含作為參數傳給被調服務方法的數據及作為輸出返回的數據。這些數據是如何序列化的?
通信雙方都能理解的序列化格式為JavaScript對象表示法(JSON)。 JSON是一種基於文本的格式,專門用於在不同層次間傳遞對象的狀態。 JavaScript支持JSON,可通過JavaScript的eval函數將JSON兼容的字符串轉換為JavaScript對象。然而,如果JavaScript字符串代表自定義對象的狀態,那麼開發者應確保具有相應類的定義。
ASP.NET AJAX網絡堆棧要負責為每個遠程傳遞的對象創建JSON字符串。在服務器端,通過專門的格式化程序類接收數據,並通過.NET反射來填充與之匹配的託管類。在返回時,.NET託管類會被序列化為JSON字符串,並發送給客戶端。腳本管理器會確保引用這些JSON字符串的類(Web服務代理類)存在於客戶端。
下面給出一個描述對象狀態的JSON格式的示例:
{ "ID":< /SPAN>"ALFKI", "Company< SPAN style="COLOR: #800000">":"Alfred Futterkiste"}
這個字符串說明該對像有兩個屬性:ID和Company,存儲的是以字符串的形式序列化的值。如果某個屬性被賦予一個非基本類型的值(如自定義對象),那麼該值會以遞歸方式序列化為JSON。
JSON與XML
相比XML,JSON更精煉,更適合JavaScript語言。
應用程序特定的Web服務
在默認情況下,ASP.NET Web服務收發的是SOAP數據包(而不是JSON數據包),通過Web服務描述語言(Web Services Description Language,WSDL)文檔來暴露其協定。 AJAX應用程序上下文中的ASP.NET XML Web服務是如何工作的呢?
可以通過ASP.NET AJAX應用程序的web.config文件來修改接收asmx請求的HTTP處理程序,將這些調用重定向給能夠理解JSON流的HTTP處理程序。這意味著ASP.NET XML Web服務可以是一種雙重的服務,即可接受和處理SOAP請求,也可針對JSON請求。在配置層,我們可以禁用SOAP支持,並隱藏用於對外公開該服務功能的WSDL文件。
如果要使用支持JSON的ASP.NET Web服務,則需要刪除XML,因為在調用ASP.NET Web服務時,我們不處理SOAP和XML。針對AJAX應用程序的ASP.NET Web服務不採用SOAP消息。
遠程編程接口的定義
協定(contract)用於定義服務器端端點暴露給調用者的內容。如果希望以ASP.NET Web服務的形式實現,則不嚴格要求存在實際的協定。但如果ASP.NET 3.5中的WCF服務,那麼協定就必須存在。總而言之,以接口形式設計的公共API會使代碼更整潔。在實現該接口的類創建完畢後,有關服務器API接口的工作就結束了。這樣我們就可以發布這個遠程API,並使ASP.NET AJAX運行庫來管理來自客戶端的調用。
對於ASP.NET Web服務,我們通過純粹的接口來定義協定,使該接口包含與服務器API有關的方法和屬性。下面給出一個簡單的服務:
using System;
public interface ITimeService
{
DateTime GetTime();
string GetTimeFormat(string format);
}
這兩個方法構成了可以在客戶端調用的服務器API。
實現已約定的接口
ASP.NET Web服務通常通過派生自基類WebService的.NET類來實現:
using System.Web.Services;
public class TimeService : WebService, ITimeService
{
...
}
注意,沒有必要一定要從基類WebService派生,這個基類主要用於直接訪問一些常用的ASP.NET對象(如Application和Session)。如果不需要直接訪問這些ASP.NET內部的對象,即使不從WebService類派生也能創建ASP.NET Web服務。這種情況下,我們可通過HttpContext對象來間接地使用ASP.NET內部的對象。
協定的發布
從本質來說,發布給定的服務器協定,就是生成一個嵌在頁面中的腳本能夠調用的JavaScript代理類。如果服務器API通過Web服務實現,我們要向ASP.NET AJAX頁面的腳本管理器註冊該Web服務。此外,我們還要在web.config文件中添加一個特殊的asmx請求HTTP處理程序。
Web服務的遠程調用
Web服務提供了服務器端代碼的宿主環境,以便在響應客戶端的操作時進行調用。服務中的Web方法指向應用程序特定的代碼。
AJAX Web服務的創建
為ASP.NET AJAX應用程序定制的Web服務比其他ASP.NET Web服務要小。 ASP.NET AJAX Web服務與傳統的ASP.NET XML Web服務間存在兩方面的差異。
首先,若使用ASP.NET AJAX Web服務,那麼為滿足特定應用程序的需要,我們要設計ASP.NET AJAX Web服務的協定,而不是配置公共服務的行為。目標應用程序就是Web服務的宿主。其次,我們必須使用一個新的特性(attribute)來聲明這種Web服務的類,而在常規的ASP.NET XML Web服務中這是不允許的。
最終的效果是,ASP.NET AJAX Web服務可能有兩套公共接口:一套是基於JSON對接口,由宿主ASP.NET AJAX應用程序使用;另一套是基於SOAP的接口,暴露給客戶端,任何平台都能訪問該服務的URL。
ScriptService特性(attribute)
為創建ASP.NET AJAX Web服務,第一步是要建立標準的ASP.NET Web服務項目,隨後導入System.Web.Script.Services命名空間:
using System.Web.Script.Services;
namespace Core35.WebService
{
[WebService(Namespace="http://Core35.book/")]
[WebServiceBinding(ConformsTo=WsiProfiles.BasicProfile1_1)]
[ScriptService]
public class TimeService : System.Web.Services.WebService, ITimeService
{
...
}
}
ScriptService特性是使ASP.NET XML Web服務與ASP.NET AJAX Web服務間產生差異的關鍵。該特性指出,該服務旨在接受來自基於JavaScript客戶端代理的調用。
阻塞SOAP客戶端
一旦創建AJAX Web服務,便可以ASMX資源的形式發布它。默認情況下,它會有公共的URL,能夠由AJAX客戶端調用,同時也能被SOAP客戶端和工具發現和使用。但我們可禁用SOAP客戶端和工具。為此,只需在web.config文件中添加以下設置:
< webSevices>
<protocols>
<clear />
protocols>
webServices>
這段簡單的設置能禁用ASP.NET Web服務定義的所有協議(包括SOAP),使該服務只能響應JSON請求。
注意,如果添加這些設置,則不能夠通過瀏覽器的地址欄來調用Web服務,以便進行簡單地測試。類似地,我們也不能為URL添加?wsdl後綴來調用WSDL。
Web服務方法的定義
客戶端頁面能夠調用Web服務類中帶有WebMethod特性的公共方法。在默認情況下,這些方法要通過HTTP動作POST來調用,以JSON對象的形式返回其值。我們可通過一個可選特性ScriptMethod來更改單個方法的默認設置。
ScriptMethod特性帶有3個屬性,見下表:
由於涉及安全性和性能問題,因謹慎使用ScriptMethod特性,下面的代碼使用了該特性,但未修改默認設置:
[ WebMethod]
[ScriptMethod]
public DateTime GetTime()
{
...
}
WebMethod特性是必選的,而ScriptMethod特性是可選的。
AJAX Web服務的註冊
為在客戶端發起對ASP.NET Web服務的調用,我們只需要XMLHttpRequest、目標Web服務的URL和JSON流的管理功能。為方便起見,所有功能都包裝在映射到遠程編程接口的JavaScript代理類中。該代理類會由ASP.NET AJAX框架自動生成,並註入到客戶端。
為使內建的引擎生成所需的JavaScript代理和輔助類,我們應在需要AJAX Web服務的頁面中,向腳本管理器控件註冊該Web服務:
<asp:ScriptManager ID=< SPAN style="COLOR: #800000">"ScriptManager1" runat="server">
<Services>
<asp:ServiceReference Path="~/WebServices/TimeService.asmx" />
< /Services>< BR>asp:ScriptManager>
對於每個要綁定到頁面的Web服務,我們添加一個ServiceReference標籤,將Path屬性設為對應asmx資源的URL。對於每個服務引用,都會在客戶端自動生成一個額外的