之前遇到一个要求,需要能够取消一个正在进行中的Web Service。这也是我第一次遇到这个功能,不过不难,我想。既然ASP.NETAJAX的客户端与服务器端通信完全通过Microsoft AJAX Library的异步通信层进行,那么我们只要得到正在请求WebService的Sys.Net.WebRequest对象,调用其abort方法就可以了。但是究竟应该如何得到这个对象呢?于是我粗略地阅读了一下代码。   首先假设有如下的Web Service方法定义(DemoService.asmx):`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
[ScriptService]`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
public class DemoService  : System.Web.Services.WebService`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
{`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
    [WebMethod]`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
    public string DemoMethod()`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
    {`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
        return "Hello World";`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
    }    `ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
}`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
  访问DemoService.asmx/jsdebug(或者将其使用ScriptManager引用到页面中之后)就能够得到如下的代理(片断、经过排版)类。`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
var DemoService = function()`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
{`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
    DemoService.initializeBase(this);`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
    this._timeout = 0;`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
    this._userContext = null;`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
    this._succeeded = null;`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
    this._failed = null;`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
}`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
DemoService.prototype =`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
{`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
    DemoMethod:function(succeededCallback, failedCallback, userContext)`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
    {`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
        return this._invoke(`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
            DemoService.get_path(),`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
            'DemoMethod',`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
            false,`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
            {},`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
            succeededCallback,`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
            failedCallback,`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
            userContext);`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
    }`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
}`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
DemoService.registerClass('DemoService',Sys.Net.WebServiceProxy);`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
...`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
  显然,这个代理类继承了Sys.Net.WebServiceProxy类,于是我就把目光转向了其中的_invoke方法:`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
function Sys$Net$WebServiceProxy$_invoke(`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
    servicePath, methodName, useGet, params, onSuccess, onFailure, userContext) {`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
    // validation omitted`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
    ...`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
    `ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
    return Sys.Net.WebServiceProxy.invoke(`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
        servicePath,`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
        methodName,`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
        useGet,`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
        params,`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
        onSuccess,`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
        onFailure,`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
        userContext,`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
        this.get_timeout());`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
}`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
  这下又将操作委托给了Sys.Net.WebServiceProxy.invoke静态方法,继续看代码:`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
Sys.Net.WebServiceProxy.invoke = function Sys$Net$WebServiceProxy$invoke(`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
    servicePath, methodName, useGet, params, onSuccess, onFailure, userContext, timeout) {`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
    // validation omitted`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
    ...`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
    // Create a web request to make the method call`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
    var request = new Sys.Net.WebRequest();`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
    // preparing request omitted`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
    ...`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
    request.invoke();`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
    function onComplete(response, eventArgs) {`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
        // method body omitted`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
    }`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
    return request;`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
}`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
  嗨,这不就是我所需要的Sys.Net.WebRequest对象吗?原来想要得到这个对象那么简单,于是我就写下了下面的代码:`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
var request = DemoService.DemoMethod(onComplete);`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
  然后在必要时:`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
request.abort();`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
  执行,出现了错误:request为undefined,为什么DemoMethod方法调用没有返回request对象?跟踪了代码之后,不大不小地晕了一下,原来问题出在这里:`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
DemoService._staticInstance = new DemoService();`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
...`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
DemoService.DemoMethod = function(onSuccess,onFailed,userContext)`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
{`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
    DemoService._staticInstance.DemoMethod(onSuccess,onFailed,userContext);`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
}`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
  虽然早就知道WebService代理会在类上创建一个Singleton对象,并且创建静态方法再委托给那个实例上的相应方法,却一直没有意识到这个细节。在上面的静态方法中,居然是直接调用了DemoMethod方法,却没有将结果返回出来,真让我哭笑不得了一下。`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
  不过问题时非常容易解决的,只要使用如下的方式在客户端调用WebService方法就可以了:`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
var request = DemoService._staticInstance.DemoMethod(onComplete);`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
  不过这个做法似乎……有些奇怪?那么您也可以这样:`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
var demoService = new DemoService();`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
var request = demoService.DemoMethod(onComplete);`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7
  在这里,重新创建一个demoService对象似乎有些多余,不过在某些时候也是非常有用的做法。例如,您需要将操作分为两类,一类的超时时间为5秒,而另一类为10秒,因此您就可以创建两个代理对象,分别设置不同的超时时间。因为超时时间我们只能在Service的级别上设置,而不能在调用方法时指定。`ÃÚO¿ Ì6xéwww.netcsharp.cn1C“72—Ãç7