本文來自《ASP.NET AJAX程式設計 第II卷:用戶端Microsoft AJAX Library相關》的第三章《非同步呼叫Web Service和頁面中的類方法》,請同時參考本章的其他文章。
3.4 保持使用者上下文
“非同步”執行意味著原本從頭到尾執行的函數被攔腰截斷,分成了兩個不同的函數。而這兩個函數之間的聯絡往往又非常緊密,例如有些時候我們需要在後一個函數(即回呼函數)中訪問前一個函數中計算出來的變數,或是在後一個函數中得到前一個函數執行時的上下文等資訊。特別地,若是幾個不同的非同步函數均提供了同一個回呼函數進行處理,我們一般還要在回呼函數中知道是哪個函數引發的這次回調。為了滿足這些需求,程式自然產生了使用者內容相關的概念。
ASP.NET AJAX非同步通訊層所提供的非同步呼叫模型中同樣提供了對傳遞使用者上下文資訊的支援。我們還使用一個簡單的樣本程式示範其具體的實現。
程式的功能並不複雜:兩個按鈕都將非同步呼叫伺服器端的同一個Web Service並指定同一個回呼函數,取得伺服器端目前時間之後顯示出來,同時顯示出來的還有使用者點擊了哪個按鈕的資訊。3-7和圖3-8所示,注意其中使用者內容相關的不同。
圖3-7點擊第一個按鈕取得伺服器端目前時間
圖3-8點擊第二個按鈕取得伺服器端目前時間
Web Service的聲明如下,返回當前伺服器端時間而已:
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService]
public class UserContextService : System.Web.Services.WebService
{
[WebMethod]
public string GetServerDateTime()
{
return DateTime.Now.ToString();
}
}
頁面中的ScriptManager控制項引用了該Web Service,以便產生其用戶端調用代理:
<asp:ScriptManager ID="sm" runat="server">
<Services>
<asp:ServiceReference Path="Services/UserContextService.asmx" />
</Services>
</asp:ScriptManager>
介面元素也不複雜:前兩個按鈕將分別調用上面定義的Web Service;後面的id為result的<div />則用來顯示調用結果:
<input id="btnGetServerDateTime1" type="button" value="Get ServerDate Time 1"
onclick="return btnGetServerDateTime1_onclick()" />
<input id="btnGetServerDateTime2" type="button" value="Get ServerDate Time 2"
onclick="return btnGetServerDateTime2_onclick()" />
<div id="result"></div>
兩個按鈕的click事件的處理函數如下:
function btnGetServerDateTime1_onclick() {
UserContextService.GetServerDateTime(onSucceeded, onFailed, "Button 1");
}
function btnGetServerDateTime2_onclick() {
UserContextService.GetServerDateTime(onSucceeded, onFailed, "Button 2");
}
注意其中粗體部分——唔,似乎前面剛剛總結出來的用戶端調用Web Service代理的文法:[NameSpace].[ClassName].[MethodName](param1, param2 …, onSucceeded, onFailed)又有了新的變化:在成功回呼函數和失敗回呼函數後面又多了一個參數,這正是本樣本程式要示範的使用者上下文參數,這裡我們分別將其設定為“Button 1”和“Button 2”。
這樣,用戶端調用Web Service代理的文法就變為:
[NameSpace].[ClassName].[MethodName](param1, param2 …, onSucceeded, onFailed, userContext)
相應地,onSucceeded()回呼函數的簽名也有所變化,在方法傳回值參數之後添加了一個代表使用者內容物件的參數。在本樣本程式中,我們將這個上下文參數(即“Button 1”和“Button 2”)簡單地顯示出來,注意代碼中的粗體部分:
function onSucceeded(result, context) {
$get("result").innerHTML =
"<strong>Current Server DateTime: </strong>" + result
+ "<br /><strong>User Context: </strong>" + context;
}
這樣即完成了本樣本程式。需要注意的是,使用者上下文不僅僅可以傳遞字串,就像在這個樣本程式中的一樣,還可以傳遞複雜的JavaScript對象,例如:
var contextObj = {
Name: "Dflying",
Age: 88,
DateOfBirth: new Date()
};
SomeNamespace.SomeClass.SomeMethod(param1, param2, onSucceeded,
onFailed, contextObj);
然後在onSucceeded()回呼函數中,我們即可訪問到傳遞過來的使用者內容物件:
function onSucceeded(result, context) {
var name = context.Name;
var age = context.Age;
var dateOfBirth = context.DateOfBirth;
}