一、Sys.Net.ServiceMethod -> Sys.Net._WebMethod

在CTP版本中,Sys.Net.ServiceMethod是客户端访问Web Services的基础类,它继承于Sys.Net.WebMethod。同样继承于Sys.Net.WebMethod的还有 Sys.Net.PageMethod,它用于访问PageMethod,这个类在RTM版本中被取消了。现在,客户端用于访问Web Service的类已经变成了Sys.Net._WebMethod(从命名上来看,很明显它不希望用户直接使用这个类),而且在使用上也有了很大的变 化。

我们先来回忆一下CTP中Sys.Net.ServiceMethod的使用方式。如下:
var  serviceMethod  =   new  Sys.Net.ServiceMethod(url, methodName, appUrl);

serviceMethod.invoke(
    parameters,
    onMethodComplete,
    onMethodTimeout, 
    onMethodError,
    onMethodAborted,
    userContext,
    timeoutInterval,
    priority);

而在RTM版本中,Sys.Net._WebMethod的使用方式如下:
var  method  =   new  Sys.Net._WebMethod(proxy, methodName, fullName, useGet);
method._execute(params, onSuccess, onFailure, userContext);

CTP版本中Sys.Net.ServiceMethod中的invoke方法还有一个重载,在RTM版本中就不存在了。在 Sys.Net._WebMethod的构造函数中,出现了一个“proxy”参数,这是什么呢?我们来看一下method._execute方法的代 码。如下:
function  Sys$Net$_WebMethod$_execute(params) {
    
return   this ._invokeInternal.apply( this , arguments);
}

不知道各位朋友看到这段代码的时候感觉如何?真正工作的代码其实是_invokeInternal方法,_execute方法在这里根本没有 起什么作用。其实它们两个的关系似乎就相当于CTP版本中Sys.Net.WebMethod类中的invoke和_invoke方法,只是 _execute并没有起到一个“调整参数”的作用,因此CTP里的“重载”也就不复存在了。莫非在以后的版本中,_execute方法真的也会提供一个 方法重载?

既然真正工作的代码是_invokeInternal,我们就来看一下它的代码。如下:
 _invokeInternal方法

上面代码中onComplete的逻辑和《深入Atlas系列:客户端网络访问基础结构(上) - WebRequest的工作流程与生命周期》 中的模版代码非常的相似。可以看出,只有在得到结果时,才会使用onSuccess回调函数,否则无论Timeout,Error还是Abort都会使用 onFailure回调函数。其实这段代码在处理错误时有个问题:请注意代码的第84-90行,这是用户没有提供onFailure回调函数时 response出错时的处理。在这段代码里,默认了result是Error对象。这是一个一点道理也没有的假设。试想,如果服务器返回了503 Service Unavailable,目前的逻辑会使用户得到一个Javascript错误。按理应该给用户一个正确的提示,那么我们该怎么办?

由于这段代码被写死在类库里,我们无法轻易修改,目前我只想到一个颇为复杂的方法:重新定义一个WebRequestExecutor,如果遇到了 “(statusCode < 200) || (statusCode >= 300)”并且contentType不是“application/json”的时候,则构造一个假的response对象,设定其 contentType为“application/json”,并使其body为一个能够构造出Sys.Net.WebServiceError对象的 JSON字符串。不得不感叹,这真是一个“令人发指”的错误。

万幸的是,如果我们提供了onFailure回调函数,就不会执行这段逻辑了,这才是最方便而且最正确的做法。

在上面的代码中使用了RTM中新增的proxy,关于它的使用还需要再看一个方法。细心的朋友应该发现了RTM中的WebMethod构造函数并没有接 受一个url作为参数,因为它会从proxy中获得。我们来看一下Sys.Net._WebMethod的getUrl方法。代码如下:
function  Sys$Net$_WebMethod$getUrl(params) {
    
// / <param name="params"></param>
     // / <returns type="String"></returns>
     var  e  =  Function._validateParams(arguments, [
        {name: 
" params " }
    ]);
    
if  (e)  throw  e;

    
if  ( ! this ._useGet  ||   ! params) params  =  {};

    
return  Sys.Net.WebRequest._createUrl( this ._proxy._get_path()  +   " /js/ this ._methodName, params );
}

Sys.Net.WebRequest._createUrl静态方法的作用是构造一个url,它会根据第二个参数声称Query String,并拼接在第一个参数上。


二、Sys.Net.ServiceMethod.invoke -> Sys.Net._WebMethod._invoke

很显然,以前的Sys.Net.ServiceMethod.invoke静态方法也会发生改变。在RTM中,与之对应的方法变成了Sys.Net._WebMethod._invoke,使用方法如下:
Sys.Net._WebMethod._invoke(
    proxy, 
    methodName, 
    fullName,
    useGet,
    params
    onSuccess,
    onFailure,
    userContext);

与CTP中的实现类似,它会构造一个Sys.Net._WebMethod对象,并调用它的_execute方法。代码非常短也非常简单,在 这里就不进行“分析”了。需要注意的是,由于Sys.Net._WebMethod._execute方法取消了“重载”,因此 Sys.Net._WebMethod._invoke方法也只有一种使用方法了。



最后,我们再来总结一下一些参数的定义。

首先是proxy,它提供了默认的onSuccess回调函数、onFailure回调函数以及userContext和timeout的定义,另外也需要提供Web Services的路径:
proxy  =  
{
    get_defaultSuccessedCallback: 
function ()  //  optional
    {
        
return   function () { ... }
    },
    get_defaultFailedCallback: 
function ()  //  optional
    {
        
return   function () { ... }
    },
    get_defaultUserContext: 
function ()  //  optional
    {
        
return  ...
    },
    get_timeout: function() // optional
    {
        
return ...
    },

    _get_path: 
function ()  //  required
    {
        
return  ...
    }
}

另外还有onSuccess和onFailure两个回调函数的签名:
function  onSuccess(result, userContext, fullMethodName)
{
    ...
}

function  onFailure(errorObj, userContext, fullMethodName)
{
    ...
}