【IT168专稿】
当我们不需要状态(state)
当我们不要求我们的应用程序来保持状态时,我们可以使用基本的HTML 和 JavaScript,为我们的服务器上面的代码提供异步呼叫。不使用状态这一方法的好处就是它非常轻巧——我们不再要求服务器完全回传。
ASP.NET AJAX通过使用JavaScript,为在服务器上面调用代码提供了一个丰富的结构。我们有能力异步地调用ASP.NET Web Service或者WCF Service方法,ASP.NET Web Service 或者 WCF Service方法都被安装在了服务器上面——所有的都没有围着服务器转。
在看任何代码之前,首先看一下怎样在Web Service上访问方法。在这篇文章前面(使用了状态的部分)已经知道ScriptManager控件有多重要,因为它能定义一个ScriptManager控件的Services子元素,以及给服务器上的服务增添一个引用,所以它变得更好。在代码1中,我们为People Web Service补充了一个引用,此People Web Service是一个ASP.NET Web Service.
代码1: 参考一个Web Service
<asp:ScriptManager当运行这个代码时将看到引用了URL,此URL和Web Service有同样的地址,然而,它上面附加有一个标记。JavaScript文件是一个自动生成的代理,为了从客户上的JavaScript代码中调用Web Services方法。我们不能在Web Services中使用这个功能,我们必须明确地定义:通过使用ScriptService属性(在System.Web.Scripts.Services命名空间里可以找到,)我们的Web Service可以被客户JavaScript调用,代码2显示了这些。
ID="sm"
runat="server">
<Services>
<asp:ServiceReference
Path="~/WebServices/PeopleWebService.asmx" />
</Services>
</asp:ScriptManager>
代码2: 允许一个Web Services的方法被client JavaScript调用
[ScriptService]
public class PeopleWebService : System.Web.Services.WebService {
// ....
}
现在建立了Web Service and ScriptManager,接着再创建某些JavaScript代码,此代码将简单地从服务器上面重新找到当前的数据和时间。(如代码3)
代码3: 异步调用一个Web Service中的一个method
Collapse在代码3中,当点击输入按钮时,我们调用了一个被称为GetServerTime() 的功能,在这个功能中,我们调用了方法GetServerTime ,此方法GetServerTime 被定义在PeopleWebService.asmx 文件中。我们访问了JavaScript 服务中的方法,好像这些服务是静态定义的类型一样(例如WebServiceName.NameOfMethod)。当我们从服务返回某些数据时要调用的功能,当服务超时或者出错时我们该怎么办?OnSuccessCallback功能产生了参数结果,结果就是返回的任何数据类型的变量名称——它可能是一个 阵列,整数,或者其它……在这种情况下,我们返回了一个字符串——然后我们将那个字符串显示在一个示警框中(如代码3所示).
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="ServerTime.aspx.cs"
Inherits="No_State_ServerTime" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Server Time</title>
<script type="text/javascript">
function GetServerTime() {
PeopleWebService.GetServerTime(OnSuccessCallback, OnServiceTimeout,
OnServiceError);
}
function OnSuccessCallback(result) {
alert(result);
}
function OnServiceTimeout(result) {
alert(result);
}
function OnServiceError(result) {
alert(result);
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager
ID="sm"
runat="server">
<Services>
<asp:ServiceReference
Path="~/WebServices/PeopleWebService.asmx" />
</Services>
</asp:ScriptManager>
<input
type="button"
value="Get Server Time"
onclick="GetServerTime()" />
</form>
</body>
</html>
图1: 调用一个Web Service中一个method的结果

现在已经讨论了Web Service的方法是怎样被调用的,下面要讨论的就是:什么样的数据通过网线被发送到客户,更重要的是,是怎样被发送的客户的。当调用Web Service方法时,我们使用JavaScript Object Notation (JSON)将数据返回到客户。为什么使用JSON的原因很简单,它比发送被串行化的XML更加容易,不像XML那样需要从语法上分析——可以自然地执行JSON(只有调用代码是安全的,我们不需要把令人厌烦的脚本通过网络发送给我们的用户)。图10中,当调用了图7中的OnSuccessCallback时,我们检查了被发送给客户的数据。意需要注意的是:在下面的例子中,我们将看一些更复杂的、在网络上传输的数据。
图2: 看看在使用JSON时通过网络发送了什么

此刻,通过使用JSON,我们只给客户发送了一些简单的字符串数据类型,现在给客户发送一个定制的类型。当给客户返回复杂的、定制的类型时,需要要让系统知道:我们打算向客户发送什么样的类型,因此我们要为Web Service增添另一个属性——GenerateScriptType(typeof(MyType)),这个属性位于System.Web.Script.Services命名空间。在进一步操作之前,我们先应该看一下Person Web Service代码后置的档案(代码4)。
代码4: PersonWebService.asmx后面的代码
Collapse
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Web;
using System.Web.Configuration;
using System.Web.Script.Services;
using System.Web.Services;
using System.Web.Services.Protocols;
[WebService(Namespace = "http://gbarnett.org/services")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService]
[GenerateScriptType(typeof(Person))]
public class PeopleWebService : System.Web.Services.WebService {
public static string _conn
= WebConfigurationManager.ConnectionStrings["CodeProjectConn"]
.ConnectionString;
public PeopleWebService() { }
[WebMethod(Description="Gets a list of all the People")]
public Person[] GetPeople() {
List personList = new List();
using (SqlConnection sqlConn = new SqlConnection(_conn))
using (SqlCommand sqlCmd
= new SqlCommand("SELECT PersonId, FirstName, LastName FROM People",
sqlConn)) {
sqlConn.Open();
SqlDataReader sqlRdr = sqlCmd.ExecuteReader();
while (sqlRdr.Read()) {
personList.Add(new Person((int)sqlRdr.GetInt32(0),
sqlRdr.GetString(1) as string,
sqlRdr.GetString(2) as string));
}
}
return personList.ToArray();
}
[WebMethod(Description = "Returns the time on the server")]
public string GetServerTime() {
return DateTime.Now.ToLongDateString() + ", " +
DateTime.Now.ToLongTimeString();
}
}
代码5: Person type的定义
using System;我们对GetPeople方法感兴趣,GetPeople方法返回一堆类型Person(Person类型代码显示在代码6中)。对于下面一个例子将调用GetPeople这个方法,然后重新叙述项目,输出一个HTML无序表(如代码6)。
/// <SUMMARY>
/// Person entity
/// </SUMMARY>public class Person {
private int _personId;
private string _firstName;
private string _lastName;
public Person() { }
public Person(int personId, string firstName, string lastName) {
_personId = personId;
_firstName = firstName;
_lastName = lastName;
}
public int PersonId {
get { return _personId; }
}
public string FirstName {
get { return _firstName; }
set { _firstName = value; }
}
public string LastName {
get { return _lastName; }
set { _lastName = value; }
}
}
Collapse
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="PeopleList.aspx.cs"
Inherits="NoStateViewPeople" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
<script type="text/javascript">
function GetPeople() {
PeopleWebService.GetPeople(OnCompleteCallback, OnServiceTimeout,
OnServiceError);
}
function OnCompleteCallback(result) {
for(i = 0; i < result.length; i++) {
$get("people").innerHTML += "<li>" + result[i].LastName + ", " +
result[i].FirstName + "</li>";
}
}
function OnServiceTimeout(result) {
alert(result);
}
function OnServiceError(result) {
alert(result);
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager
ID="sm"
runat="server">
<Services>
<asp:ServiceReference
Path="~/WebServices/PeopleWebService.asmx" />
</Services>
</asp:ScriptManager>
<input
type="button"
value="Get People"
onclick="GetPeople()" />
<ul
id="people"></ul>
</form>
</body>
</html>
因为调用GetPeople()方法的结果会返回一个阵列,结果变量的类型就是类型Person 阵列。有意义的是:我们可以使用C#代码(例如:result[i].FirstName)访问Person类型的属性。
总结不使用state的情况,当调用People Web Service 的GetPeople()方法时,可以看一下JSON 对象图 (如代码7)的形式。
图3: JSON 对象图

总结
通过这篇文章可以看到了ASP.NET AJAX的能力和灵活性。我们研究了当使用ASP.NET AJAX结构时,使用state和没有使用state这两种方法的优点和缺点,我们也检查了每一个方法中通过网络发送的数据。