本文来自《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,这是为了让程序能够从客户端访问服务器端的用户个性化属性。<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浑然天成般紧密结合。