本文來自《ASP.NET AJAX程式設計 第II卷:用戶端Microsoft AJAX Library相關》的第五章《應用程式服務和本地化》。
讓我們通過編寫一個完整的樣本程式學習如何配置並使用ASP.NET AJAX的ProfileService對象來實現讀取、修改並儲存使用者個人化資訊的功能。在這個樣本程式中,我們將藉助本章第2節中實現的使用者身份認證功能,並基於該實現為已登入使用者提供讀取、修改並儲存使用者個人化資訊的功能。
該樣本程式的功能並不複雜:其中自訂了3個使用者個人化屬性,分別用來儲存頁面中一段文本的顏色、字型大小和字型。程式在載入時將自動為已登入使用者向伺服器請求這3個使用者個人化屬性,並在成功載入之後應用到頁面中的文本上。使用者也可以在程式中修改這些使用者個人化屬性並儲存,成功儲存後,頁面中文本的樣式也將被更新。自然,所有的過程都是以Ajax無重新整理方式進行的。
5.4.1 啟用使用者個人化應用程式服務
首先,在本章第2節中使用者身份認證功能樣本程式所在的同一個Web網站中,修改其web.config設定檔的<configuration />\<system.web />節,在其中定義如下的使用者個人化屬性。這並不是ASP.NET AJAX引入的新特性,而是ASP.NET 2.0的內建支援:
<profile enabled="true">
<properties>
<add name="FontColor" type="System.String"
defaultValue="black"/>
<add name="FontSize" type="System.String"
defaultValue="12px"/>
<add name="FontFamily" type="System.String"
defaultValue="tahoma"/>
</properties>
</profile>
可以看到,在上述配置中,我們定義了3個System.String類型的使用者個人化屬性:FontColor、FontSize和FontFamily,分別將用來儲存樣本程式頁面中文本的顏色、字型大小和字型,這3個使用者個人化屬性也都提供了預設值。
然後要為ASP.NET AJAX啟用從用戶端訪問這些伺服器端使用者個人化屬性的支援。同樣是在web.config設定檔中,在<configuration />節下添加如下配置:
<system.web.extensions>
<scripting>
<webServices>
<profileService enabled="true"
readAccessProperties="FontColor,FontSize,FontFamily"
writeAccessProperties="FontColor,FontSize,FontFamily" />
</webServices>
</scripting>
</system.web.extensions>
可以看到,其中<profileService />標籤的enabled屬性被設定為true,這是為了讓程式能夠從Client Access Server端的使用者個人化屬性。<profileService />標籤的readAccessProperties和writeAccessProperties屬性則分別用來表示暴露給用戶端讀取或修改的使用者個人化屬性名稱,使用者個人化屬性名稱之間用逗號分開。通過合理地設定readAccessProperties和writeAccessProperties屬性,我們可以僅僅挑選必要的使用者個人化屬性暴露給用戶端,即增強了程式的安全性。
5.4.2 樣本程式的UI部分
在Visual Studio的設計器中,本樣本程式的介面5-9所示。
圖5-9 樣本程式在Visual Studio設計器中的介面
在圖5-9中可以看到,頁面主要分為左右兩個部分。其中左側用來讓已登入使用者佈建3個使用者個人化屬性,右側的那段文本則用來示範左側屬性設定的變化。
當然,在添加任何UI元素之前,最先要做的就是在頁面中定義ScriptManager控制項:
<asp:ScriptManager ID="sm" runat="server" />
頁面左邊設定3個使用者個人化屬性的表單的代碼如下:
<label for="tbFontColor">Font Color:</label>
<input id="tbFontColor" type="text" /><br />
<label for="tbFontSize">Font Size:</label>
<input id="tbFontSize" type="text" /><br />
<label for="tbFontFamily">Font Family:</label>
<input id="tbFontFamily" type="text" /><br />
<input id="btnUpdateProfile" type="button" value="Update Profile"
onclick="return btnUpdateProfile_onclick()" />
注意其中3個文字框的id,將在稍後的程式中用到。上述代碼中的按鈕用來觸發儲存修改後的使用者個人化屬性。
右側顯示文本的面板代碼如下(為節省篇幅,代碼中省略了大部分文字):
<div id="content">
It has been a week since I updated the blog last time and
…………
- hopefully that can be of great helps :)
</div>
這個<div />也應用了一些CSS樣式:
#content
{
float: right;
width: 260px;
border: 1px solid black;
padding: 5px;
}
再定義一個空的<div />,用來輸出一些程式運行中的狀態資訊。請留意其id,將在稍後用到:
<div id="result">
</div>
這樣即完成了程式的UI部分。
5.4.3 樣本程式的JavaScript代碼部分
完成了程式的UI部分之後,自然來到了JavaScript代碼部分,以便控制各個UI元素的行為。在頁面中ScriptManager的出現位置之後添加一個<script />標籤,接下來所有的指令碼內容均將置於該標籤中:
<script type="text/javascript">
</script>
首先,我們來設定ProfileService對象的3個預設回呼函數,這3個回呼函數分別將在成功載入使用者個人化資訊、成功儲存使用者個人化資訊以及調用失敗時被調用:
Sys.Services.ProfileService.set_defaultLoadCompletedCallback(onLoadCompleted);
Sys.Services.ProfileService.set_defaultSaveCompletedCallback(onSaveCompleted);
Sys.Services.ProfileService.set_defaultFailedCallback(onProfileFailed);
讓我們依次分析這3個回呼函數的實現。成功載入使用者個人化資訊的回呼函數——onLoadCompleted()。其中先給出了一段“成功載入”的提示資訊,然後調用一個名為updateContentStyleAndProfileInputs()的輔助函數更新頁面右側文本的樣式以及3個屬性文字框中的內容:
function onLoadCompleted(numProperties, userContext, methodName) {
// 設定使用者個人化屬性載入成功資訊
$get("result").innerHTML = "Profile Loaded!";
// 更新常值內容樣式以及屬性文字框中的內容
updateContentStyleAndProfileInputs();
}
updateContentStyleAndProfileInputs()輔助函數的代碼如下。其中首先取得了3個使用者個人化屬性的值,然後設定到右側的文本上,最後設定頁面左側屬性文字框中的文本。注意其中粗體部分對ProfileService對象properties屬性的使用:
function updateContentStyleAndProfileInputs() {
// 取得當前的個使用者個人化屬性
var fontColor = Sys.Services.ProfileService.properties.FontColor;
var fontSize = Sys.Services.ProfileService.properties.FontSize;
var fontFamily = Sys.Services.ProfileService.properties.FontFamily;
// 設定常值內容的樣式
var contentElem = $get("content");
contentElem.style.color = fontColor;
contentElem.style.fontSize = fontSize;
contentElem.style.fontFamily = fontFamily;
// 設定屬性文字框中的內容
$get("tbFontColor").value = fontColor;
$get("tbFontSize").value = fontSize;
$get("tbFontFamily").value = fontFamily;
}
成功儲存使用者個人化資訊的回呼函數——onSaveCompleted()與onLoadCompleted()非常類似。同樣是先給出提示,然後調用前面給出的updateContentStyleAndProfileInputs()輔助函數更新程式的介面:
function onSaveCompleted(numProperties, userContext, methodName) {
// 設定使用者個人化屬性儲存成功資訊
$get("result").innerHTML = "Profile Saved!";
// 更新常值內容樣式以及屬性文字框中的內容
updateContentStyleAndProfileInputs();
}
而調用失敗時的回呼函數——onProfileFailed()則並沒有什麼具體的實現代碼,僅僅將程式切換到調試狀態而已:
function onProfileFailed(error, userContext, methodName) {
debugger;
}
然後編寫pageLoad()函數,該函數將在用戶端應用程式載入完畢後被ASP.NET AJAX用戶端架構自動調用。在該函數中,我們會調用ProfileService對象的load()方法,以便在程式初始化完畢後立即再次調用伺服器端使用者個人化服務並讀取使用者的個人化屬性。注意其中調用load()方法時並沒有提供任何參數:
function pageLoad(sender, args) {
Sys.Services.ProfileService.load();
}
提示:若想隨頁面HTML代碼的載入一起發送這些使用者個人化屬性的值,那麼可以按照如下代碼修改ScriptManager(或ScriptManagerProxy)控制項的聲明。注意其中粗體部分即聲明了要積極式載入的使用者個人化屬性:
<asp:ScriptManager ID="sm" runat="server">
<ProfileService LoadProperties="FontColor,FontSize,FontFamily" />
</asp:ScriptManager>
至於頁面左邊設定使用者個人化屬性的表單中的按鈕(id為btnUpdateProfile),其click事件的處理函數代碼如下。不過是首先收集使用者輸入的新樣式,然後調用ProfileService對象的save()方法而已:
function btnUpdateProfile_onclick() {
// 取得文框中的內容,並更新使用者個人化屬性
Sys.Services.ProfileService.properties.FontColor = $get("tbFontColor").value;
Sys.Services.ProfileService.properties.FontSize = $get("tbFontSize").value;
Sys.Services.ProfileService.properties.FontFamily = $get("tbFontFamily").value;
// 儲存修改後的使用者個人化屬性
Sys.Services.ProfileService.save();
}
前面我們已經設定了ProfileService對象的3個預設回呼函數,所以在非同步呼叫load()和save()方法返回之後,ProfileService對象將自動根據剛剛結束的非同步呼叫的完成狀況選擇並調用上述3個回呼函數中的某一個。
到此為止,我們即完成了整個樣本程式的編寫。
5.4.4 運行樣本程式
在運行該樣本程式之前,我們要保證先在本章第2節中的樣本程式頁面中成功登入(5-5和圖5-6所示)。然後導航至本樣本程式頁面,你將看到5-10所示的介面。
圖5-10 樣本程式的初始介面
在圖5-10中可以看到,程式已經成功載入了當前登入用的3個使用者個人化屬性。頁面左側的3個文字框也分別顯示這些屬性值。而頁面右側的文本則反映出了當前這3個屬性所表現出的樣式。
修改一下“Font Color”、“Font Size”和“Font Family”這三個文字框中的屬性,並點擊下方的“Update Profile”按鈕。隨著一次Ajax方式的非同步更新,這3個使用者個人化屬性將被提交給伺服器,頁面右邊的文本也會同時反映出這3個使用者個人化屬性變化的結果。5-11所示。
圖5-11 修改並更新3個使用者個人化屬性後,頁面右邊的文本樣式也會隨之變化
這3個使用者個人化屬性已經被提交到伺服器端儲存起來,即使使用者關閉了瀏覽器,下次再登入時也會看到同樣的、5-11所示的介面。
通過這樣一個完整的樣本程式,我們示範了使用ASP.NET AJAX的ProfileService對象實現Ajax方式讀取、修改並儲存使用者個人化資訊的方法。有了ProfileService對象的協助,我們即可在用戶端以Ajax方式使用ASP.NET 2.0提供的使用者個人化應用程式服務,讓ASP.NET AJAX與ASP.NET 2.0渾然天成般緊密結合。