简言之,WEB SERVICE其实就是在Web之上提供服务(SERVICE〕。客户端可以调用远程服务器端函数并得到结果,就像RMI,DCOM和COBRA一样。不同的是客户端和服务器端的“对话”使用的是业界标准而不是JAVA或Microsoft独有的技术。由于采用了HTTP作缺省通讯协议,使得WEB SERVICE可以透过各个企业,公司的防火墙,真正实现跨INTERNET的分布式计算。也因为HTTP,使得WEB SERVICE在本质上一些先天的限制,就像其它的WEB应用程序一样。HTTP是一种无态的(STATELESS)通讯协议,所以在HTTP之上的WEB SERVICE如何保持“状态(STATE)”就成为一个有趣的话题。在这里,我想就这个问题做一些讨论。
从一个简单的例子看WEB SERVICE的“无态性”
在Microsoft提供的VISUAL STUDIO.NET中,集成的开发环境将很多WEB SERVICE的繁琐细节隐藏了起来,尽量的想使开发者感到方便和简单,就像在开发普通的类(CLASS)和函数那样。但是你千万不能被表象所蒙蔽,从而导致一些最基本的错误。请看下面这个小例子。
class Student : System.Web.Services.WebService
{
private String name;
public String Name
{
get{return name;}
set{name=value;}
}
}
一眼看上去,这个Student类没有什么毛病。另外,你在客户端想这样的使用它。
localhost.Student student = new localhost.Student();
student.setName("Lao Wang");
String myInfo = student.getName();
...
这下应该没有问题了吧。但当你运行客户端程序的时候,你发现结果和你预料的不一样。getName函数返回值是NULL。奇怪,刚刚设置的"Lao Wang"哪儿去了呢?
如果你遇到这样的问题,那说明你被集成环境给蒙蔽了,没有知道程序究竟是怎么执行的。看起来你只创建了一个Student实例(Object),并两次调用它的函数。但实际情况却非如此。你没有创建一个Student实例,你只是创建了Student类的代理类的实例(Proxy Class)。Student类的实例是在服务器端创建的,而且是两次。你在客户端两次的函数调用在服务器端生成了两个实例,每个实例响应一次函数调用。两个实例之间没有任何联系,所以你把第一个实例的Name设为"Lao Wang"对于第二个实例来讲是全然无知的。现在,你可能体会到"无态"的涵义了吧。
如果你知道一些WEB SERVICE的背景REMOTING的话,这一点就更好理解了。WEB SERVICE的实例创建是属于REMOTING中"单一调用"方式的(SINGLE CALL)。意思是每一次的函数调用都会在服务器端创建一个新的实例。(REMOTING还支持Singleton和ClientActivation两种方法)
那么解决如何保存"状态"呢?就前面的这个小问题来说,你可以这样修改一下程序。
class Student : System.Web.Services.WebService
{
private String name;
[WebMethod (EnableSession=true)]
public String getName()
{
return (String)Session["NAME"];
}
[WebMethod (EnableSession=true)]
public void setName(String aName)
{
Session["NAME"] = aName;
}
}
...
localhost.Student student = new localhost.Student();
student.CookieContainer = new System.Net.CookieContainer();
student.setName("Lao Wang");
String myInfo = student.getName();
...
这样一改,问题就解决了。其"奥秘"在于你引入了ASP.NET中的"会话状态"管理机制(SESSION STATE MANAGEMENT)。如果你做过ASP或ASP.NET开发的话,你就回马上明白这一点。就象我前面所说, WEB SERVICE是在WEB上提供的SERVICE,WEB上的许多东西在WEB SERVICE里同样适用。"会话状态"管理机制是WEB SERVICE中最普遍采用的一种保存"状态"的方法,它将信息存在于服务器端,所以适宜保存比较敏感的信息,例如信用卡号码,银行帐号什么的。并且SESSION中可以存放各种复杂的数据结构甚至是COM对象的实例,这使得它可以用来实现很复杂的状态保存。