最近开始着手学习ASP.NET AJAX,在园里看了很多关于这方面的文章,自己也曾买了关于ASP.NET AJAX的书籍,本文我将借鉴于老赵的WebCast
深入浅出系列课程第五讲以记学习笔记的形式和大家一起学习关于ASP.NET AJAX
客户端访问Web Service
参数类型的序列化与反序列化内容.
由于涉及到是示例较多,本文我将分为两部分.
本文的内容包括
● 复杂参数类型基本使用方式
● 生成复杂参数类型的客户端代理
● 客户端代理的作用
● 使用JavaScriptConverter
● 自定义JavaScriptConverter
一、复杂参数类型基本使用方式
首先我们定义一个Employee类:
Emploee类
1
public class Employee
2

{
3
/**//// <summary>
4
/// 作为参数的类型一定要有默认的构造函数
5
/// </summary>
6
public Employee()
7
{
8
}
9
10
public Employee(string name, string sex, string age)
11
{
12
this.Name = name;
13
this.Sex = sex;
14
this.Age = age;
15
}
16
17
private string _name;
18
public string Name
19
{
20
get
{ return _name; }
21
set
{ _name = value; }
22
}
23
24
private string _sex;
25
public string Sex
26
{
27
get
{ return _sex; }
28
set
{ _sex = value; }
29
}
30
31
private string _age;
32
public string Age
33
{
34
get
{ return _age; }
35
set
{ _age = value; }
36
}
37
}
接下来我们定义一个WebService的方法,提供给客户端调用,返回复杂类型(Employee) ;
1
/**/
/// <summary>
2
/// EmployeeWebService 的摘要说明
3
/// </summary>
4
[WebService(Namespace
=
"
http://tempuri.org/
"
)]
5
[WebServiceBinding(ConformsTo
=
WsiProfiles.BasicProfile1_1)]
6
[ScriptService]
7

public
class
EmployeeWebService : System.Web.Services.WebService
{
8
9
public EmployeeWebService ()
{
10
11
//如果使用设计的组件,请取消注释以下行
12
//InitializeComponent();
13
}
14
15
[WebMethod]
16
public Employee GetEmployeeOne()
17
{
18
return new Employee("beniao", "boy", "22");
19
}
20
21
[WebMethod]
22
public Employee GetEmployeeTwo(Employee employee)
23
{
24
return new Employee(employee.Name, employee.Sex, employee.Age);
25
}
26
}
这其实是很简单的,我就不做过多的说明。我门先为ScriptManager指向我门上面开发的Web Service。并放置两个按扭来实现调用,最后我们将返回的结果显示在一个DIV上。
1
<
asp:ScriptManager
ID
="ScriptManager1"
runat
="server"
>
2
<
Services
>
3
<
asp:ServiceReference
Path
="EmployeeWebService.asmx"
/>
4
</
Services
>
5
</
asp:ScriptManager
>
6
7
<
input
id
="Button1"
type
="button"
value
="无参数交互"
onclick
="GetEmployeeOne();"
/>
8
<
input
id
="Button2"
type
="button"
value
="带参数交互"
onclick
="GetEmployeeTwo();"
/>
9
<
br
/><
br
/>
10
<
div
id
="Result"
style
="width:230px;height:30px;font-weight:bold;font-size:medium;background-color:#CCC;"
></
div
>
客户端的调用是怎么定义的呢?分别有发送请求的函数和回调函数:
1
<
script type
=
"
text/javascript
"
>
2
function
GetEmployeeOne()
3

{
4
EmployeeWebService.GetEmployeeOne(CallBack);
5
}
6
function
GetEmployeeTwo()
7

{
8
//使用JSON进行传输
9
var employee =
{"Name":"Yuang", "Sex":"girl", "Age":"21"};
10
EmployeeWebService.GetEmployeeTwo(employee , CallBack);
11
}
12
13
//
回调函数
14
function
CallBack(employee)
15

{
16
var obj=document.getElementById("Result");
17
obj.innerHTML=String.format("Name:{0} Sex:{1} Age:{2}",
18
employee.Name,
19
employee.Sex,
20
employee.Age);
21
}
如上面所介绍,演示了一个关于复杂参数的基本使用,运行结果如下所示:

二、生成复杂参数类型的客户端代理
这一步其实是很简单的.代码我们就重用上面的代码就可以了.新建立一个页面,把上面示例的页面代码Copy过来作适当的修改就OK了.我门先看看客户端的代码定义:
1
<
asp:ScriptManager
ID
="ScriptManager1"
runat
="server"
>
2
<
Services
>
3
<
asp:ServiceReference
Path
="EmployeeWebService.asmx"
InlineScript
="true"
/>
4
</
Services
>
5
</
asp:ScriptManager
>
6
7
<
input
id
="Button2"
type
="button"
value
="使用客户端代理"
onclick
="GetEmployee();"
/>
8
<
br
/><
br
/>
9
<
div
id
="Result"
style
="width:230px;height:30px;font-weight:bold;font-size:medium;background-color:#CCC;"
></
div
>
同上一个例子一样,我们将ScriptManager指向EmployeeWebService.asmx这个Web服务,下面是JS定义,服务器端的发方法为了在客户端调用方法,在客户端会生成方法的代理,那怎么使用客户端方法的代理呢?下面我们来看看通过客户端代理的使用,代码如下定义:
<
script
type
="text/javascript"
>
function GetEmployee()

{
//使用客户端代理替换JSON字符串
var employee = new Employee();
employee.Name="beniao";
employee.Sex="boy";
employee.Age="22";
EmployeeWebService.GetEmployeeTwo(employee , CallBack);
}
function CallBack(employee)

{
var obj=document.getElementById("Result");
obj.innerHTML=String.format("Name:{0} Sex:{1} Age:{2}",
employee.Name,
employee.Sex,
employee.Age);
}
</
script
>
我们很清楚的看到上面示例中我们使用的是一个Employee对象,而非上个示例中的JSON字符串了,其实使用客户端代理和JSON字符串是完全等价的. 下面是两者的定义:
1
//
使用JSON进行传输
2

var
employee
=
{"Name":"beniao", "Sex":"boy", "Age":"22"}
;
3
----------------------------------------------------------------------
4
//
使用客户端代理替换JSON字符串
5
var
employee
=
new
Employee();
6
employee.Name
=
"
beniao
"
;
7
employee.Sex
=
"
boy
"
;
8
employee.Age
=
"
22
"
;
9
那Employee这个客户端代理是怎么生成的呢?这并非是我们在服务端定义的Employee类,不过与它还是有很大的关系,那这个客户端代理是怎么生成的以及通过什么样的方法可以查看到这个代理的生成呢?前面我们在为ScriptManager引入Web服务的时候后面加入了这样一个属性:InlineScript="true",通过设置它我们就能够在客户端显示生成的客户端代理.那怎么查看呢?运行你所开发的页面,右键查看源文件,里面有下面的定义(不同的代理会有所不同,下面是本例中生成的代理):
1
EmployeeWebService.prototype
=
{
2
GetEmployeeOne:function(succeededCallback, failedCallback, userContext)
{
3
return this._invoke(EmployeeWebService.get_path(), 'GetEmployeeOne',false,
{},succeededCallback,failedCallback,userContext); },
4
GetEmployeeTwo:function(employee,succeededCallback, failedCallback, userContext)
{
5
return this._invoke(EmployeeWebService.get_path(), 'GetEmployeeTwo',false,
{employee:employee},succeededCallback,failedCallback,userContext); }}
6
EmployeeWebService.registerClass(
'
EmployeeWebService
'
,Sys.Net.WebServiceProxy);
7
EmployeeWebService._staticInstance
=
new
EmployeeWebService();
8

EmployeeWebService.set_path
=
function
(value)
{ EmployeeWebService._staticInstance._path = value; }
9

EmployeeWebService.get_path
=
function
()
{ return EmployeeWebService._staticInstance._path; }
10

EmployeeWebService.set_timeout
=
function
(value)
{ EmployeeWebService._staticInstance._timeout = value; }
11

EmployeeWebService.get_timeout
=
function
()
{ return EmployeeWebService._staticInstance._timeout; }
12

EmployeeWebService.set_defaultUserContext
=
function
(value)
{ EmployeeWebService._staticInstance._userContext = value; }
13

EmployeeWebService.get_defaultUserContext
=
function
()
{ return EmployeeWebService._staticInstance._userContext; }
14

EmployeeWebService.set_defaultSucceededCallback
=
function
(value)
{ EmployeeWebService._staticInstance._succeeded = value; }
15

EmployeeWebService.get_defaultSucceededCallback
=
function
()
{ return EmployeeWebService._staticInstance._succeeded; }
16

EmployeeWebService.set_defaultFailedCallback
=
function
(value)
{ EmployeeWebService._staticInstance._failed = value; }
17

EmployeeWebService.get_defaultFailedCallback
=
function
()
{ return EmployeeWebService._staticInstance._failed; }
18
EmployeeWebService.set_path(
"
/Web/EmployeeWebService.asmx
"
);
19

EmployeeWebService.GetEmployeeOne
=
function
(onSuccess,onFailed,userContext)
{EmployeeWebService._staticInstance.GetEmployeeOne(onSuccess,onFailed,userContext); }
20

EmployeeWebService.GetEmployeeTwo
=
function
(employee,onSuccess,onFailed,userContext)
{EmployeeWebService._staticInstance.GetEmployeeTwo(employee,onSuccess,onFailed,userContext); }
21
var
gtc
=
Sys.Net.WebServiceProxy._generateTypedConstructor;
22

if
(
typeof
(Employee)
===
'
undefined
'
)
{
23
var Employee=gtc("Employee");
24
Employee.registerClass('Employee');
25
}
通过上面的客户端代理我们可以查看到,在客户端为我们注册了一个gtc("Employee"),生成这样的代理之后,我们就可以在客户端通过代理的方法来使用Employee类了.这或许可以说是一种映射吧(个人意见).要让服务器在运行的时候生成客户端的代理其实很简单,上面说这么多归根到底就一个代码实现,我们只需要在服务端方法上加入[GenerateScriptType(typeof(Employee))]这样一句话就可以了,完整定义如下:
1
[WebMethod]
2
[GenerateScriptType(
typeof
(Employee))]
//
在客户端生成一个复杂的代理
3
public Employee GetEmployeeTwo(Employee employee)
4

{
5
return new Employee(employee.Name, employee.Sex, employee.Age);
6
}
三、客户端代理的作用
事实上我们在使用客户端代理的时候,有很多对象对我们开发都是很有用的,其实在使用客户端代理的实质就是为对象在客户端生成了一个"__type"标记,如我们上面使用Employee类,在客户端生成的"__type"标记为:
__type
=
"
Employee
"
;
下面我们来看看一个实例,由于上面我们定义了Employee,这里我们就定义一个User做为实例的对象.
1
public abstract class User
2

{
3
public abstract string GetSalary();
4
}
5

6
//
/ <summary>
7
//
/ 全职
8
//
/ </summary>
9
public class FullTime : User
10

{
11
public override string GetSalary()
12
{
13
return "全职:10000.0";
14
}
15
}
16

17
//
/ <summary>
18
//
/ 兼职
19
//
/ </summary>
20
public class PartTime : User
21

{
22
public override string GetSalary()
23
{
24
return "兼职:2000.0";
25
}
26
}
我们上面定义了User类,并抽象了一个方法getSalary(),在服务器端这里是可以实现多态的,接下来我们为该对象(User)对象开发一个Web Service;
1
[WebService(Namespace
=
"
http://tempuri.org/
"
)]
2
[WebServiceBinding(ConformsTo
=
WsiProfiles.BasicProfile1_1)]
3
[ScriptService]
4

public
class
UserWebService : System.Web.Services.WebService
{
5
6
public UserWebService ()
{
7
8
//如果使用设计的组件,请取消注释以下行
9
//InitializeComponent();
10
}
11
12
13
[WebMethod]
14
[GenerateScriptType(typeof(FullTime))]
15
[GenerateScriptType(typeof(PartTime))]
16
public string GetUserSalary(User user)
17
{
18
return user.GetSalary();
19
}
20
}
在客户端我们通过传递不同的字类对象在WebService里通过多态的方式去调用具体的实现类.我们现在来看看在客户端怎么通过__type标记来实现这种"多态"的调用.
1
<
script type
=
"
text/javascript
"
>
2
function getSalary()
3

{
4
var user = new Object();
5
user.__type = $get("UserType").value;
6
UserWebService.GetUserSalary(user,onSucceeded);
7
}
8
9
function onSucceeded(result)
10

{
11
$get("Result").innerHTML = result;
12
}
13
</
script
>
我们在客户端通过指定不同的对象(也就是为__type标记指定不同的客户端类型),服务器端根据标记选择反序列化的目标类型来实现"多态"效果的调用;
1
<
asp:ScriptManager
ID
="ScriptManager1"
runat
="server"
>
2
<
Services
>
3
<
asp:ServiceReference
Path
="UserWebService.asmx"
/>
4
</
Services
>
5
</
asp:ScriptManager
>
6
<
select
id
="UserType"
>
7
<
option
value
="FullTime"
>
全职
</
option
>
8
<
option
value
="PartTime"
>
兼职
</
option
>
9
</
select
>
10
11
<
input
id
="btnSalary"
type
="button"
value
="计算工资"
onclick
="getSalary();"
/><
br
/>
12
<
div
id
="Result"
style
="width:230px;height:30px;font-weight:bold;background-color:#CCC;"
></
div
>
通过下拉选择控件中选择不同的类型(FullTime,PartTime),动态的指定__type标记的值.将调用结果呈现在DIV里显示出来,运行结果如下所示;

关于客户端访问Web Service--参数类型的序列化与反序列化的前部分就先介绍到这里,后续部分我将尽快记录下来,我很喜欢以写文章的这种方式来做笔记,喜欢大家多多支持与指点.文章里的不妥之处还望前辈们多多指正,谢谢.
文章里使用的示例代码我将在后半部分完成后提供给大家参考.
-----------------------------------------------------