使用ASP.NET AJAX异步调用Web Service和页面中的类方法(1):调用Web Service、调用页面中的类方法

本文来自《ASP.NET AJAX程序设计 第II卷:客户端Microsoft AJAX Library相关》的第三章《异步调用Web Service和页面中的类方法》,请同时参考本章的其他文章


3.1 调用Web Service

之所以ASP.NET AJAX将Web Service提高到了如此的重要位置上,让它几乎成为了ASP.NET AJAX服务器端逻辑最受推荐的实现方式,是因为Web Service天生就是纯粹为了业务逻辑而设计的。我们都知道,Web Service没有提供什么“花哨”的用户界面,而是心无旁骛地专注于程序逻辑上的实现,这恰好和ASP.NET AJAX客户端编程模型所倡导的“将表现层和业务逻辑层彻底分开”的理念不谋而合——客户端的ASP.NET AJAX框架用来处理程序所有的界面、与用户交互功能,服务器端则仅仅提供纯粹的数据,不涉及任何表现样式。

借助于ASP.NET AJAX异步通讯层所自动生成的Web Service客户端访问代理,在表现层代码,也就是JavaScript中调用Web Service获取数据成为了一件异常简单的事情——其表现出的优雅甚至让我们不敢相信:难道Ajax程序也能写得这么简单?

接下来就让我们通过一个简单的示例程序了解一下在ASP.NET AJAX应用程序中使用JavaScript异步调用Web Service的方法。出于演示的目的,程序的功能非常简单:用户在页面的文本框中输入名字,然后点击旁边的按钮,如图3-1所示。

图3-1 用户在界面中输入自己的名字

程序将借助ASP.NET AJAX异步通讯层以Ajax方式把用户的名字发送至服务器端的Web Service。随后该Web Service在服务器端根据用户的名字生成一段问候信息并发送回客户端,客户端收到服务器响应之后,将把这段问候信息显示出来,如图3-2所示。

图3-2 程序显示出来自服务器的问候信息

让我们先从服务器端的Web Service入手。新建一个名为SimpleWebService的Web Service类并在其中声明一个普通的Web Service方法——SayHello()。该方法将接受一个名为name的参数,并生成一条问候信息返回:

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class SimpleWebService : System.Web.Services.WebService
{
    [WebMethod]
    public string SayHello(string name)
    {
        return string.Format("Hello {0}!", name);
    }
}

这就是个普通的Web Service,没有任何不一样之处。注意不要忘记为SayHello()方法添加[WebMethod]属性,这是每个Web方法都必需的。

为了让ASP.NET AJAX生成该Web Service的客户端异步调用代理,进而允许我们在JavaScript代码中直接调用该方法,我们还要再为SimpleWebService类添加[ScriptService]属性,这一部分才是ASP.NET AJAX为Web Service提供的附加功能(注意代码中粗体部分):

//…………
[ScriptService]
//…………
public class SimpleWebService : System.Web.Services.WebService
{
    //…………
}

提示:我们也可以直接为需要暴露给客户端的Web Service方法添加[ScriptService]属性,而不必将其添加到Web Service类上。

[ScriptService]属性位于System.Web.Script.Services命名空间中,如果需要的话,还要添加如下的using语句:

using System.Web.Script.Services;

下面列出完整的SimpleWebService Web Service代码如下,注意其中粗体部分:

using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Web.Script.Services;
 
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService]
public class SimpleWebService : System.Web.Services.WebService
{
    [WebMethod]
    public string SayHello(string name)
    {
        return string.Format("Hello {0}!", name);
    }
}

完成了Web Service编写之后,我们来先行测试一下——开发过程中不断地进行阶段性测试有助于尽快发现潜在的问题,并将其扼杀在萌芽中。如果一切顺利的话,那么测试该Web Service时可以看到如图3-3所示的结果。

图3-3 测试Web Service时的界面

接下来即可用ASP.NET AJAX异步调用这个Web Service了。首先新建一个ASP.NET页面。当然,该页面所在的Web站点必须已经配置好了ASP.NET AJAX的支持,详细配置方法请参考本书第I卷。在该页面上添加一个ScriptManager服务器端控件,这是每一个ASP.NET AJAX应用程序都必不可少的:

<asp:ScriptManager ID="sm" runat="server">
</asp:ScriptManager>

为了让ASP.NET AJAX为前面的Web Service生成客户端异步调用代理,我们需要在ScriptManager控件中添加该Web Service的引用:

<asp:ScriptManager ID="sm" runat="server">
    <Services>
        <asp:ServiceReference Path="Services/SimpleWebService.asmx" />
    </Services>
</asp:ScriptManager>

这种声明语法隐约中传递了这样的含义:Web Service的客户端异步调用代理脚本将由ScriptManager控件管理——这非常自然,不是么?ScriptManager就是用来管理(manage)脚本(script)的呀!关于<Services />标签以及<asp:ServiceReference />标签的详细使用方法,在本书第I卷中已经有详细讨论,这里不赘。

随后声明程序界面中必不可少的UI元素:

<input id="tbName" type="text" />
<input id="btnInvoke" type="button" value="Say Hello" 
    onclick="return btnInvoke_onclick()" />
<div id="result"></div>

其中id为tbName的<input />作为文本框,用来让用户输入名字;id为btnInvoke的<input />作为按钮,点击将触发异步调用Web Service;id为result的<div />则用来将Web Service返回的问候内容显示出来。这些id均将在稍后用到。

上面代码中btnInvoke按钮定义了click事件的事件处理函数,该函数的实现如下。注意这是客户端JavaScript代码:

function btnInvoke_onclick() {
    var theName = $get("tbName").value;
    SimpleWebService.SayHello(theName, onSayHelloSucceeded);
}

首先用$get("tbName").value取得了用户在文本框中输入的文字。然后第二句SimpleWebService.SayHello()即调用了ASP.NET AJAX异步通讯层自动为SimpleWebService生成的客户端代理。这是本示例程序中最为重要的一句——与用C#在Web Service中声明的SayHello()方法签名相比,其参数个数以及顺序均完全一样,甚至调用语法也没什么特别——都是[NameSpace].[ClassName].[MethodName](param1, param2 …, callbackFunction)。由此我们能够看出ASP.NET AJAX异步通讯层为降低开发者学习曲线、提高开发者生产效率所做出的努力及良苦用心。

参考:关于用来取得DOM元素引用的$get()方法,请参考本卷第1章中的介绍。

不过客户端代理还提供了额外的一个参数——异步调用的回调函数名称,这里为onSayHelloSucceeded。该回调函数将在服务器端异步调用成功返回后由ASP.NET AJAX异步通讯层自动调用。onSayHelloSucceeded()回调函数的代码如下:

function onSayHelloSucceeded(result) {
    $get("result").innerHTML = result;
}

onSayHelloSucceeded()回调函数的result参数代表了本次异步调用的返回结果,即Web Service方法的返回值,这里即为包含了用户名字的问候语。该回调函数将由ASP.NET AJAX异步通讯层自动调用,其result参数也会由ASP.NET AJAX异步通讯层传递进来,无需我们任何手工控制。在本示例程序的onSayHelloSucceeded()回调函数中,我们只是简单地将这句问候语显示在id为result的<div />中。

参考:ASP.NET AJAX异步通讯层为Web Service自动生成的客户端代理以及相应的回调函数还提供了更多的参数和配置功能,这些都将在本章中详细介绍。

这样就完成了本示例程序的所有代码编写。运行该程序,如果一切顺利的话,你将看到如图3-1和图3-2所示的界面。

ASP.NET AJAX的异步通讯层在本示例程序中小试牛刀,纵观整个示例程序的实现代码,我们不难看出该架构的强大功能以及为我们开发者细心周全的考虑。虽然在实际开发中,我们很难遇到本示例程序中这样简单的功能。但麻雀虽小,五脏俱全,理解了这样一个简单的示例程序之后,我们完全可以举一反三,根据开发过程中的实际需要编写不同的Web Service以及客户端调用代码,轻松地完成工作。

总结:想要使用ASP.NET AJAX在客户端JavaScript中异步调用服务器端Web Service,我们需要:

  1. 为Web Service类或需要暴露给客户端的Web Service方法添加[ScriptService]属性;
  2. 为Web Service中需要暴露给客户端的方法添加[WebMethod]属性;
  3. 在页面中的ScriptManager控件中添加对该Web Service的引用;
  4. 在客户端使用如下JavaScript语法调用该Web Service:
    [NameSpace].[ClassName].[MethodName](param1, param2 ......, callbackFunction)
  5. 为客户端异步调用指定回调函数,在回调函数中接收返回值并进一步处理。

 

3.2 调用页面中的类方法

让客户端JavaScript直接能够异步调用到服务器端的Web Service,这看起来真的是个不错的主意——理想化的分层Ajax应用程序就应该这样嘛!不过作为被ASP.NET服务器端开发模型“宠坏”了的我们,更加熟悉的方法是直接将方法写在ASP.NET页面中,比如处理页面中的某个服务器端按钮Click事件的代码,就可能这样调用定义在同一张页面代码文件中的方法:

protected void Button1_Click(object sender, EventArgs e)
{
    myLabel.Text = this.GetTextForLabel();
}
 
public string GetTextForLabel()
{
    // ......
    return "Some Text";
}

对于那些“遗留”的ASP.NET应用程序来讲,这样直接定义在ASP.NET页面中的方法更是相当常见。若是仅仅为了配合ASP.NET AJAX的客户端访问Web Service功能,就将这些方法一一迁移到Web Service中,岂不是非常麻烦?

好在ASP.NET AJAX在设计时考虑到了这个问题,并提供给我们一种作为替代的选择。ASP.NET AJAX异步通讯层能够将声明在ASP.NET页面中的公有的类方法(C#中的static,VB.NET中的Shared)当作Web Service中声明的方法一样对待,为其生成类似的客户端调用代理。

我们还是通过一个实例程序来了解这个功能。该示例程序的功能与界面均与前面一节中的完全一致,唯一的不同就是,客户端异步调用的不再是某个Web Service,而是定义在ASP.NET页面中的类方法。

首先是定义在ASP.NET页面中的类方法,完整的方法声明如下:

[WebMethod]
public static string SayHelloFromPage(string name)
{
    return string.Format("Hello {0}!", name);
}

特别需要注意的是,若要让ASP.NET AJAX为其生成客户端调用代理,那么一定要为该方法添加[WebMethod]属性。

然后是ScriptManager控件,注意粗体部分代码设置了EnablePageMethods属性为true,这也是让客户端能够直接调用服务器端页面方法所必需的。若你忘记了设定该属性,那么程序将无法完成预期功能:

<asp:ScriptManager ID="sm" EnablePageMethods="true" runat="server" />

程序界面中的UI元素和前一个节中的示例程序完全一致,这里不赘:

<input id="tbName" type="text" />
<input id="btnInvoke" type="button" value="Say Hello" 
    onclick="return btnInvoke_onclick()" />
<div id="result"></div>

而本示例程序中按钮的click事件处理函数以及异步调用的回调函数则需要一定的修改,如下所示:

function btnInvoke_onclick() {
    var theName = $get("tbName").value;
    PageMethods.SayHelloFromPage(theName, onSayHelloSucceeded);
}
 
function onSayHelloSucceeded(result) {
    $get("result").innerHTML = result;
}

注意上述代码中的粗体部分。可以看到,调用页面方法代理时统一的前缀为PageMethods。接下来是页面方法的名称,这里为SayHelloFromPage(),其参数列表和C#中方法的定义一致,额外的一个参数表示本次异步调用的回调函数。即语法为:

PageMethods.[MethodName](param1, param2 …, callbackFunction);

这样即完成了本示例程序,运行一下,我们将会看到如图3-1和图3-2一样的界面。

总结:想要使用ASP.NET AJAX在客户端JavaScript中异步调用定义在ASP.NET页面中的方法,我们需要:

  1. 将该方法声明为公有(public);
  2. 将该方法声明为类方法(C#中的static,VB.NET中的Shared),而不是实例方法;
  3. 为该方法添加[WebMethod]属性;
  4. 将页面中ScriptManager控件的EnablePageMethods属性设置为true;
  5. 在客户端使用如下JavaScript语法调用该页面方法:
    PageMethods.[MethodName](param1, param2 …, callbackFunction);
  6. 为客户端异步调用指定回调函数,在回调函数中接收返回值并进一步处理。
posted on 2007-06-05 08:51  Dflying Chen  阅读(22941)  评论(75编辑  收藏  举报