客户端访问Web Service方法的一个细节

之前遇到一个要求,需要能够取消一个正在进行中的Web Service。这也是我第一次遇到这个功能,不过不难,我想。既然ASP.NET AJAX的客户端与服务器端通信完全通过Microsoft AJAX Library的异步通信层进行,那么我们只要得到正在请求Web Service的Sys.Net.WebRequest对象,调用其abort方法就可以了。但是究竟应该如何得到这个对象呢?于是我粗略地阅读了一下代码。

  首先假设有如下的Web Service方法定义(DemoService.asmx):

[ScriptService]
public class DemoService : System.Web.Services.WebService
{
[WebMethod]
public string DemoMethod()
{
return "Hello World";
}
}

  访问DemoService.asmx/jsdebug(或者将其使用ScriptManager引用到页面中之后)就能够得到如下的代理(片断、经过排版)类。

var DemoService = function()
{
DemoService.initializeBase(this);
this._timeout = 0;
this._userContext = null;
this._succeeded = null;
this._failed = null;
}
DemoService.prototype =
{
DemoMethod:function(succeededCallback, failedCallback, userContext)
{
return this._invoke(
DemoService.get_path(),
'DemoMethod',
false,
{},
succeededCallback,
failedCallback,
userContext);
}
}
DemoService.registerClass('DemoService',Sys.Net.WebServiceProxy);
...

  显然,这个代理类继承了Sys.Net.WebServiceProxy类,于是我就把目光转向了其中的_invoke方法:

function Sys$Net$WebServiceProxy$_invoke(
servicePath, methodName, useGet, params, onSuccess, onFailure, userContext) {

// validation omitted
...

return Sys.Net.WebServiceProxy.invoke(
servicePath,
methodName,
useGet,
params,
onSuccess,
onFailure,
userContext,
this.get_timeout());
}

  这下又将操作委托给了Sys.Net.WebServiceProxy.invoke静态方法,继续看代码:

Sys.Net.WebServiceProxy.invoke = function Sys$Net$WebServiceProxy$invoke(
servicePath, methodName, useGet, params, onSuccess, onFailure, userContext, timeout) {

// validation omitted
...

// Create a web request to make the method call
var request = new Sys.Net.WebRequest();

// preparing request omitted
...

request.invoke();

function onComplete(response, eventArgs) {
// method body omitted
}

return request;
}

  嗨,这不就是我所需要的Sys.Net.WebRequest对象吗?原来想要得到这个对象那么简单,于是我就写下了下面的代码:

var request = DemoService.DemoMethod(onComplete);

  然后在必要时:

request.abort();

  执行,出现了错误:request为undefined,为什么DemoMethod方法调用没有返回request对象?跟踪了代码之后,不大不小地晕了一下,原来问题出在这里:

DemoService._staticInstance = new DemoService();
...
DemoService.DemoMethod = function(onSuccess,onFailed,userContext)
{
DemoService._staticInstance.DemoMethod(onSuccess,onFailed,userContext);
}

  虽然早就知道Web Service代理会在类上创建一个Singleton对象,并且创建静态方法再委托给那个实例上的相应方法,却一直没有意识到这个细节。在上面的静态方法中,居然是直接调用了DemoMethod方法,却没有将结果返回出来,真让我哭笑不得了一下。

  不过问题时非常容易解决的,只要使用如下的方式在客户端调用WebService方法就可以了:

var request = DemoService._staticInstance.DemoMethod(onComplete);

  不过这个做法似乎……有些奇怪?那么您也可以这样:

var demoService = new DemoService();
var request = demoService.DemoMethod(onComplete);

  在这里,重新创建一个demoService对象似乎有些多余,不过在某些时候也是非常有用的做法。例如,您需要将操作分为两类,一类的超时时间为5秒,而另一类为10秒,因此您就可以创建两个代理对象,分别设置不同的超时时间。因为超时时间我们只能在Service的级别上设置,而不能在调用方法时指定。

 感谢原创者的辛勤劳动,希望对您有所帮助,转载请注明原出处。
 您可能对 [Web Service] 的这些文章也感兴趣:

ASP.NET创建Web服务之管理Web服务状态  ASP.NET创建Web服务之声明
ASP.NET创建Web服务之发布和部署  创建数据库Web Services
HTTP 安全性和 ASP.NET Web 服务  SharePoint Web Services入门
实现一个.NET Web Services服务注册中心  实现COM组件向Web Services的转变
实现Web Service依赖倒置  创建数据库Web Services
Microsoft Releases Web Service Software Factory  ASPX页Web服务调用性能优化
WSE 3.0 文档翻译:为Web Service提供保护  新浪短信Web Service
Web Service学习笔记:创建一个示例和WebMethod特性解析  客户端访问Web Service方法的一个细节
根据托管类库创建WebService代码  使用WCF的Web编程模型开发REST风格的Web Service
有了Web Service,还需要.NET吗?  利用Web Services保持Http环境下的连接状态