本文來自《ASP.NET AJAX程式設計 第II卷:用戶端Microsoft AJAX Library相關》的第三章《非同步呼叫Web Service和頁面中的類方法》,請同時參考本章的其他文章。
3.7 伺服器端和用戶端資料類型的自動轉換
讀到這裡,細心的讀者可能已經發現了:前面的樣本程式中傳遞給Web Service以及從Web Service返回的資料的類型均為簡單的字串或是整數。可是在實際開發中,只傳遞字串或整數類型的資料顯然是不夠用的。那麼ASP.NET AJAX非同步通訊層對於伺服器端.NET類型和用戶端JavaScript類型之間的映射是否提供了一些協助工具功能呢?也就是說,在使用ASP.NET AJAX與伺服器端進行非同步通訊時,我們能不能直接傳遞諸如DateTime、DataTable乃至更加複雜的自訂類型呢?
答案自然非常令人興奮——沒有任何問題!ASP.NET AJAX非同步通訊層提供了強大的伺服器端.NET類型和用戶端JavaScript類型之間自動轉換能力,我們只要略加配置,甚至根本不需要任何配置,即可在非同步通訊的過程中傳遞包括基本類型、枚舉類型、複雜類型、集合(包括泛型集合)類型、數群組類型等資料。
若是在某些特殊情況下這類自動轉換無法滿足實際需求,我們需要更為精確地完全控制某個類型的轉換規則,那麼也不用擔心——藉助於在ASP.NET AJAX非同步通訊層強大的可擴充性,開發人員可以容易地實現自己的轉換方案,並“插入”到現有ASP.NET AJAX非同步通訊層中。關於自訂伺服器端和用戶端資料類型的轉換規則,將在第III卷中詳細介紹。
本節就將通過樣本程式介紹ASP.NET AJAX非同步通訊層所提供的伺服器端.NET類型和用戶端JavaScript類型之間的自動轉換功能。
3.7.1 基本類型
在本節中,基本類型是指數字類型(包括整型、浮點型等)、字串類型、布爾類型、時間日期類型等。對於這些類型,ASP.NET AJAX非同步通訊層能夠自動進行伺服器端.NET類型和用戶端JavaScript類型之間的轉換,無須我們任何幹預。
例如對於下面的Web Service定義,其中定義了一個名為SendSimpleTypes()的方法,分別接受整型、浮點型、字串類型、布爾類型、時間日期的六個參數。SendSimpleTypes()方法沒有什麼實際功能,僅僅起到示範的作用:
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService]
public class SimpleTypes : System.Web.Services.WebService
{
[WebMethod]
public void SendSimpleTypes(int intVar, float floatVar,
string stringVar, bool boolVar, DateTime datetimeVar)
{
// just for testing
}
}
然後在用戶端我們可以分別建立這5種類型,並嘗試通過ASP.NET AJAX非同步通訊層產生的代理傳遞到該Web Service中:
var intVar = 123;
var floatVar = 123.456;
var stringVar = "hello, this is Dflying";
var boolVar = true;
var datetimeVar = new Date();
SimpleTypes.SendSimpleTypes(
intVar, floatVar, stringVar, boolVar, datetimeVar
);
在Visual Studio中啟動調試功能,在前面定義的Web Service方法SendSimpleTypes()的第一行加上一個斷點(3-10所示)。
圖3-10在Web Service方法的第一行設定斷點
當程式運行至SendSimpleTypes()方法時,開啟Visual Studio的“Locals”視窗(Ctrl+Alt+V,L)可以看到SendSimpleTypes()方法的5個參數均已被正確地傳遞到了伺服器端。3-11所示。
圖3-11 在“Locals”視窗中查看局部變數的值
3.7.2 枚舉類型
對於枚舉類型,若是某個Web Service代理中有所使用(或者Web Service方法接受枚舉類型,或者Web Service方法返回枚舉類型)的話,ASP.NET AJAX非同步通訊層也將自動為該枚舉類型產生用戶端JavaScript版本,並負責用戶端與伺服器端類型之間的轉換,同樣無須我們任何幹預。
例如對於如下Web Service以及其中定義的GetTomorrowDay()方法,用來接受一個類型為System.DayOfWeek類型的枚舉,然後返回同樣類型的枚舉,表示下一天是星期幾:
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService]
public class EnumService : System.Web.Services.WebService
{
[WebMethod]
public DayOfWeek GetTomorrowDay(DayOfWeek today)
{
return (DayOfWeek)(((int)today + 1) % 7);
}
}
若是在頁面中引入了上面的這個名為EnumService的Web Service代理:
<asp:ScriptManager ID="sm" runat="server">
<Services>
<asp:ServiceReference Path="Services/EnumService.asmx" />
</Services>
</asp:ScriptManager>
然後在頁面中書寫如下的用戶端指令碼:
function pageLoad() {
debugger;
}
在Visual Studio中啟動調試後,程式將在ASP.NET AJAX用戶端架構初始化完畢時(即執行該pageLoad()方法)停下來(debugger語句)。
參考:關於pageLoad()方法以及ASP.NET AJAX用戶端架構的初始化過程,將在第4章中詳細介紹。關於debugger語句以及ASP.NET AJAX應用程式的調試方法和技巧,將在第III卷中詳細介紹。
這是隨便開啟一個“Watch”視窗(Ctrl+Alt+W,然後數字鍵1、2、3或者4均可),在其中輸入“System.DayOfWeek”並斷行符號確認。隨後點擊“System.DayOfWeek”一行左邊的加號表徵圖展開其中內容,即可看到ASP.NET AJAX非同步通訊層自動為該伺服器端枚舉類型產生用戶端枚舉類型中的各個屬性。3-12所示,注意其中從“Sunday”到“Saturday”的7個枚舉值。
圖3-12 ASP.NET AJAX非同步通訊層為
伺服器端System.DayOfWeek枚舉類型產生的用戶端枚舉類型
這樣,頁面中就擁有了伺服器端System.DayOfWeek枚舉類型的用戶端版本。此後,我們也可以將這個用戶端的System.DayOfWeek枚舉值直接傳遞給Web Service:
EnumService.GetTomorrowDay(System.DayOfWeek.Monday, onSucceeded);
伺服器端將收到“Monday”,當然這個“Monday”已經是伺服器端.NET類型的枚舉了,3-13所示。
圖3-13 伺服器端收到用戶端傳遞過來的System.DayOfWeek枚舉值
隨後用戶端的回呼函數將收到用戶端System.DayOfWeek枚舉類型的星期二值(“Tuesday”),3-14所示。
圖3-14 用戶端回呼函數收到伺服器返回的System.DayOfWeek枚舉值
對於我們自訂的.NET枚舉類型,ASP.NET AJAX非同步通訊層同樣將一視同仁地產生用戶端版本。例如如下表示太陽系八大行星的枚舉類型:
namespace Dflying.MyEnums
{
public enum Planets
{
Mercury,
Venus,
Earth,
Mars,
Jupiter,
Saturn,
Uranus,
Neptune
}
}
若是在Web Service方法中用到了的話,例如如下所示的一個Web Service方法,用來隨機返回八大行星中的一個:
[WebMethod]
public Planets GetRandomPlanet()
{
Random r = new Random();
return (Planets)((int)r.Next(9));
}
ASP.NET AJAX非同步通訊層將為其產生相應的用戶端代理。3-15所示(同樣是在Visual Studio的“Watch”視窗中)。
圖3-15 ASP.NET AJAX非同步通訊層為伺服器端自訂枚舉類型產生的用戶端枚舉類型
總結:想要讓ASP.NET AJAX非同步通訊層為伺服器端枚舉類型自動產生相應的用戶端枚舉類型,並在調用過程中傳遞並接收該枚舉,我們需要:
- 為Web Service類或Web Service中需要暴露給用戶端的方法添加[ScriptService]屬性;
- 為Web Service中需要暴露給用戶端的方法添加[WebMethod]屬性;
- Web Service類中的某個方法的某個參數或傳回值為該枚舉類型;
- 在頁面中的ScriptManager控制項中添加對該Web Service的引用;
- 在用戶端用如下JavaScript文法使用該枚舉類型:
[NameSpace].[EnumName].[EnumKey]