您的位置:首页 > 编程语言 > ASP

了解 ASP.NET AJAX Web 服务——ASP.NET AJAX学习笔记“出自msdn”

2011-06-24 15:09 381 查看

用 ASP.NET AJAX 调用Web 服务

Web服务是 .NET 框架的一个组成部分,为分布式系统之间的数据交换提供跨平台的解决方案。Web 服务常用于不同操作系统、对象模型和编程语言的数据发送和接收,也可用于向ASP.NET AJAX 页面中动态注入数据,或从页面向后端系统发送数据。上述所有操作都无需执行回传。
尽管通过 ASP.NET AJAX UpdatePanel控件可以方便地在任意ASP.NET 页面上启用AJAX,但有时您可能需要不通过UpdatePanel 就能动态访问服务器上的数据。本文档将介绍如何通过在ASP.NET AJAX页面中创建和使用 Web 服务达到这一目的。
本文档将重点介绍核心 ASP.NET AJAX Extensions的可用功能,以及ASP.NET AJAX Toolkit中一个启用了Web 服务、名为AutoCompleteExtender的控件。内容包括定义启用了AJAX 的Web 服务、创建客户端、以及用JavaScript 调用 Web 服务。另外我们还将学习如何直接向ASP.NET 页面方法发起 Web 服务调用。

Web服务配置

用 Visual Studio 2008 Beta 2创建一个新网站项目时,web.config 文件中有很多新内容。使用Visual Studio 前期版本的用户可能对这些内容不甚了解。这些更改内容中有一部分将asp 前缀映射到ASP.NET AJAX 控件中,以便在页面中使用这些控件,还有一些内容用于定义所需的HttpHandler 和 HttpModule。程序列表 1 列出了对 web.config 中的 <httpHandlers> 元素所做的、影响Web 服务调用的更改内容。移除了用于处理.asmx 调用的默认 HttpHandler,取而代之的是位于System.Web.Extensions.dll 程序集中的 ScriptHandlerFactory 类。System.Web.Extensions.dll 包含ASP.NET AJAX 使用的所有核心功能。
程序列表1. ASP.NET AJAX Web服务处理器配置
求消息传递了一个值为Belgium 的国家参数,而程序列表3 中的响应消息则传递了一个Customer 对象数组及其关联属性。

<httpHandlers>
<remove verb="*" path="*.asmx"/>
<add verb="*" path="*.asmx" validate="false"
type="System.Web.Script.Services.ScriptHandlerFactory,
System.Web.Extensions, Version=1.0.61025.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35"/>
</httpHandlers>


[b]程序列表2.序列化为JSON格式的Web服务请求消息[/b]

[code]
{"country":"Belgium"}
[/code]
[b]注意:操作名称定义为指向web服务的URL的一部分。此外,请求消息并不总是通过JSON提交。Web服务可使用UseHttpGet属性被设为true的ScriptMethod属性,通过请求字符串参数传递参数。[/b]

[b]程序列表3.序列化为JSON格式的Web服务响应消息[/b]

[code]
[{"__type":"Model.Customer","Country":"Belgium","CompanyName":"Maison
Dewey","CustomerID":"MAISD","ContactName":"Catherine
Dewey"},{"__type":"Model.Customer","Country":"Belgium","CompanyName":"Suprêmes
délices","CustomerID":"SUPRD","ContactName":"Pascale
Cartrain"}]
[/code]
下面将介绍如何创建能处理JSON请求消息并能用简单或复杂类型进行回应的 Web 服务。

创建启用了 AJAX 的 Web 服务

ASP.NET AJAX 框架提供了多种调用 Web 服务的方法。您可以使用AutoCompleteExtender控件(在 ASP.NET AJAX 工具箱中)或JavaScript 来达到这一目的。但在调用服务之前,必须为该服务启用AJAX,以使它能被客户端脚本代码所调用。

无论您是否熟悉 ASP.NET Web 服务,您都将发现创建并启用AJAX 的服务都很简单。.NET 框架 自 2002 年首次发布起就支持创建ASP.NET Web 服务。而ASP.NET AJAX Extensions 也额外提供了建立于.NET 框架默认的特性集基础上的AJAX 功能。Visual Studio .NET 2008 Beta 2 内含对创建 .asmx Web 服务文件的支持,并自动从System.Web.Services.WebService 类继承了关联的 code beside 类。向这个类添加方法时,必须为方法应用 WebMethod 属性,以使它们能为 Web 服务使用者所调用。

程序列表 4 将 WebMethod 属性应用于一个名为GetCustomersByCountry()的方法:

[b]程序列表4.在Web服务中使用 WebMethod属性[/b]

[WebMethod]
public Customer[] GetCustomersByCountry(string country)
{
return Biz.BAL.GetCustomersByCountry(country);
}
[b]GetCustomersByCountry()方法接受了一个国家参数,并返回一个 Customer 对象数组。传递到方法中的国家值被转发到一个业务层类,后者又调用一个数据层类以便从数据库中检索数据、用数据填充Customer对象属性并返回数组。[/b]

[b]使用 ScriptService 属性[/b]

[b]虽然添加 WebMethod 属性允许向 Web 服务发送标准 SOAP 消息的客户端调用GetCustomersByCountry()方法,但这并不能允许从外部的ASP.NET AJAX应用程序调用 JSON。要允许JSON 调用,必须对 Web 服务类应用 ASP.NET AJAX Extension 的 [b]ScriptService 属性,这样使 Web 服务能发送使用了 JSON 格式的响应消息,并允许客户端侧脚本通过发送JSON消息来调用服务。[/b][/b]

[b]程序列表 5 的示例是为一个名为CustomersService的Web 服务类应用ScriptService 属性。[/b]

[b][b]程序列表5.在启用AJAX的Web服务中使用 ScriptService属性[/b][/b]

[System.Web.Script.Services.ScriptService]
[WebService(Namespace = "http://xmlforasp.net")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class CustomersService : System.Web.Services.WebService
{
[WebMethod] public Customer[] GetCustomersByCountry(string country) { return Biz.BAL.GetCustomersByCountry(country); }
}

[b]ScriptService 属性作为表示可从 AJAX 脚本代码调用的标记。它并不真的处理任何后台的JSON 序列化或反序列化任务。绝大部分的JSON 处理任务由 ScriptHandlerFactory (在web.config 中配置)及其他相关类完成。[/b]

[b][b]使用 ScriptMethod 属性[/b][/b]


[b][b]ScriptService 是惟一一个需要在 .NET Web 服务中定义才能被 ASP.NET AJAX 页面使用的ASP.NET AJAX 属性。但另一个名为 ScriptMethod 的属性也可以直接应用于服务中的Web Methods。ScriptMethod 定义了三个属性:[b]UseHttpGet、ResponseFormatXmlSerializeString。可在下列情况下更改这些属性:某个Web Method 接受的请求类型需要更改为GET;某个 Web Method 需要以 XmlDocumentXmlElement 的格式返回原始的 XML 数据;或从某个服务返回的数据应始终序列化为XML 而非 JSON。[/b][/b][/b]

[b][b]UseHttpGet属性可在 Web Method 应接受 GET 请求而非 POST 请求时使用。请求被使用Web Method输入参数转换为QueryString 参数的URL 发送。UseHttpGet 属性的默认值为 false,且只有当操作确定为安全、没有敏感数据传递给Web 服务的情况下才能设为[b]true。程序列表 6 的示例是使用带有 UseHttpGet 属性的 ScriptMethod 属性。[/b][/b][/b]

[b][b][b]程序列表6.使用带有UseHttpGet属性的 ScriptMethod属性[/b][/b][/b]
[b][/b]
[WebMethod]
[ScriptMethod(UseHttpGet = true)]
public string HttpGetEcho(string input)
{
return input;
}
[b][b][b]当程序列表 6 中的 HttpGetEcho Web Method被调用时,被发送的标头示例如下:[/b][/b][/b]
[b][/b]
GET /CustomerViewer/DemoService.asmx/HttpGetEcho?input=%22Input Value%22 HTTP/1.1
[/code]
除了允许 Web Method 接受 HTTP GET 请求之外,在需要从某个服务而非 JSON 返回 XML 响应时也可使用ScriptMethod 属性。例如,某个 Web 服务可能从远程站点检索到一个RSS 反馈,并将其作为一个 XmlDocument 或 XmlElement 对象返回,然后客户端上就可以进行XML 数据处理。
程序列表 7 的示例是使用ResponseFormat属性指定应从Web Method 返回的XML 数据。
程序列表7.使用带有ResponseFormat属性的ScriptMethod属性
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Xml)]
public XmlElement GetRssFeed(string url)
{
XmlDocument doc = new XmlDocument();
doc.Load(url);
return doc.DocumentElement;
}


ResponseFormat也可与XmlSerializeString属性一起使用。XmlSerializeString属性有一个默认值false,表示当 [b]ResponseFormat属性设为 ResponseFormat.Xml时,除从 Web Method 返回的字符串之外的所有返回类型都被序列化为 XML。当XmlSerializeString 设为 true 时,从 Web Method 返回的所有类型,包括字符串类型,都被序列化为XML。如果ResponseFormat 属性的值为 ResponseFormat.Json,则 XmlSerializeString 属性将被忽略。[/b]
程序列表 8 的示例是使用XmlSerializeString属性强制将字符串序列化为XML。
程序列表8.使用带有XmlSerializeString属性的ScriptMethod属性
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Xml,XmlSerializeString=true)]
public string GetXmlString(string input)
{
return input;
}


调用程序列表 8 中的 GetXmlString Web Method,将返回如下所示的值:
<?xml version="1.0"?>
<string>Test</string>
[/code]尽管默认的 JSON 格式使请求和响应的总规模降到最小,并更方便为ASP.NET AJAX 客户端以跨浏览器方式使用,但当 Internet Explorer 5或更高版本等客户端应用程序需要从 Web Method 返回XML 数据时,也可以使用ResponseFormat和XmlSerializeString属性。

使用复杂类型

在程序列表 5 的示例中,从 Web 服务返回了一个名为 Customer 的复杂类型。Customer 类在内部将几个不同的简单类型定义为FirstName 和 LastName 等属性。在启用了 AJAX 的 Web Method 上使用作为输入参数或返回类型的复杂类型发送到客户端之前,它们自动被序列化为JSON 格式。但嵌套(在另一个类型内部定义)的复杂类型默认情况下未作为独立的对象提供给客户端使用。
当某个 Web 服务使用的嵌套复杂类型也需要在客户端页面中使用时,可以向此Web 服务添加ASP.NET AJAX GenerateScriptType 属性。例如,程序列表 9 中的 CustomerDetails 类就包含了表示嵌套复杂类型的Address 和 Gender 属性。
程序列表9.此处的CustomerDetails类包含两个嵌套复杂类型
public class CustomerDetails : Customer
{
public CustomerDetails()
{
}

Address _Address;
Gender _Gender = Gender.Unknown;

public Address Address
{
get { return _Address; }
set { _Address = value; }
}

public Gender Gender
{
get { return _Gender; }
set { _Gender = value; }
}
}
程序列表 9 中的 CustomerDetails类中定义的Address 和Gender 对象不会自动在客户端侧通过JavaScript 使用,因为它们是嵌套类型(Address 是类,Gender 是枚举)。如果某个在Web 服务中使用的嵌套类型必须供客户端侧使用,那么可以使用前面提到过的GenerateScriptType属性(参见程序列表 10)。如果从服务返回不同的嵌套复杂类型,可以多次添加此属性。此属性可以直接应用于Web 服务类或上述特定 Web Method。
程序列表10.使用GenerateScriptService属性定义应提供给客户端使用的嵌套类型。
[System.Web.Script.Services.ScriptService]
[System.Web.Script.Services.GenerateScriptType(typeof(Address))]
[System.Web.Script.Services.GenerateScriptType(typeof(Gender))]
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class NestedComplexTypeService : System.Web.Services.WebService
{
//Web Methods
}

通过将 GenerateScriptType属性应用于 Web 服务,Address 和 Gender 类型将自动为客户端侧的ASP.NET AJAX JavaScript 代码所用。程序列表 11 中所示的示例是通过向一个 Web 服务添加GenerateScriptType属性自动生成 JavaScript 并被发送至客户端。本文档稍后将演示如何使用嵌套复杂类型。
程序列表11.在ASP.NET AJAX页面中提供嵌套复杂类型
if (typeof(Model.Address) === 'undefined')
{
Model.Address=gtc("Model.Address");
Model.Address.registerClass('Model.Address');
}
Model.Gender = function() { throw Error.invalidOperation(); }
Model.Gender.prototype = {Unknown: 0,Male: 1,Female: 2}
Model.Gender.registerEnum('Model.Gender', true);


创建 JavaScript 代理

调用标准 Web 服务(.NET 或其他平台)通常涉及到创建一个代理对象,将您从发送 SOAP 请求和响应消息的复杂事务中屏蔽。使用ASP.NET AJAX Web 服务调用,可以轻松地创建和使用JavaScript 代理,以便轻松调用服务而无需考虑序列化及反序列化JSON 消息。通过使用 ASP.NET AJAX ScriptManager 控件,可以自动生成JavaScript 代理。
创建能调用 Web 服务的 JavaScript 代理是通过ScriptManager 的Services 属性完成的。通过此属性,可以定义一个或多个能为ASP.NET AJAX 页面异步调用、以便发送或接收数据而无需回传操作的服务。通过使用ASP.NET AJAX ServiceReference 控件并指定到控件的Path 属性的 Web 服务 URL 来定义服务。程序列表 12 中的示例是引用一个名为CustomersService.asmx 的服务。
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Services>
<asp:ServiceReference Path="~/CustomersService.asmx" />
</Services>
</asp:ScriptManager>


程序列表12.定义在ASP.NET AJAX页面使用的 Web服务
通过 ScriptManager 控件添加一个指向CustomersService.asmx的引用,将动态生成一个 JavaScript 代理并为页面所引用。使用<script> 标记嵌入代理,且通过调用CustomersService.asmx 文件和向其末尾添加 /js 动态载入它。下例演示了web.config 中禁用了调试时如何在页面嵌入JavaScript 代理:
<script src="CustomersService.asmx/js" type="text/javascript"></script>

注意:如果您想查看实际生成的 JavaScript代理的代码,可以在Internet Explorer的地址栏输入相应的.NET Web服务的URL,并在其末尾添加/js。
如果 web.config 中启用了调试,页面中将嵌入 JavaScript 代理的调试版本,如下所示:
<script src="CustomersService.asmx/jsdebug" type="text/javascript"></script>

ScriptManager 创建的 JavaScript 代理也可不使用<script>标记的src 属性引用,而是直接嵌入页面。操作方法为:将 ServiceReference控件的 InlineScript 属性设为 true(默认值为 false)。当代理未跨页面共享、且您希望减少对服务器的网络调用数量时,可以采用这一方法。InlineScript 被设为 true 时,浏览器不会缓存代理脚本。因此如果代理被一个ASP.NET AJAX 应用程序中的多个页面使用,建议将InlineScript 设为 default。使用 InlineScript 属性的示例如下:
<asp:ServiceReference InlineScript="true" Path="~/CustomersService.asmx"/>

使用 JavaScript 代理

一旦ASP.NET AJAX 页面使用 ScriptManager 控件引用某个Web 服务,便可发起对此Web 服务的调用,返回的数据可以使用回调函数处理。 Web 服务的调用通过引用其命名空间(如果有的话)、类名称和 Web Method 名称来实现。传递给 Web 服务的任何参数都可与一个处理返回数据的回调函数一起定义。
程序列表 13 中的示例是使用 JavaScript 代理调用一个名为GetCustomersByCountry()的 Web 方法。当终端用户点击页面上的一个按钮时,GetCustomersByCountry()函数即被调用。
程序列表13.用JavaScript代理调用Web服务

function GetCustomerByCountry()
{
var country = $get("txtCountry").value;

InterfaceTraining.CustomersService.GetCustomersByCountry(country,
OnWSRequestComplete);
}

function OnWSRequestComplete(results)
{
if (results != null)
{
CreateCustomersTable(results);
GetMap(results);
}
}


本调用引用了服务中定义的InterfaceTraining命名控件、CustomersService类以及GetCustomersByCountry Web Method。它传递了一个从文本框获取的国家值,以及一个应在异步 Web 服务调用返回时调用的名为OnWSRequestComplete的回调函数。OnWSRequestComplete 处理从服务返回的Customer 对象数组,并将它们转换为一个表格显示在页面上。图1 显示的是调用生成的输出。




[b]图1:通过向 Web 服务发起异步 AJAX 调用来绑定获取的数据[/b]
当某个 Web 方法应被调用但代理不应等待响应时,JavaScript 代理也可以向 Web 服务进行单向调用。例如,您可能想要调用一个Web 服务以开始一个进程(如工作流),但不想等待该服务的返回值。需要向服务发起单向调用时,可以直接省略程序列表13 中的回调函数。因为没有定义回调函数,代理对象将不会等待Web 服务返回数据。

补充:
Default.aspx

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>无标题页</title>

<script type="text/javascript">
function HelloWorld()
{
var i = Service.HelloWorld(onSuccess);
}
function onSuccess(a)
{
window.alert(a);
}
</script>
</head>
<body>
<form id="form1" runat="server"  load="HelloWorld">
<div>
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Services>
<asp:ServiceReference Path="~/Service.asmx" />
</Services>
</asp:ScriptManager>
<input type="button" onclick="HelloWorld()" value="button"/>
</div>
</form>
</body>
</html>


Service.asmx
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
// 若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消对下行的注释。
[System.Web.Script.Services.ScriptService]
public class Service : System.Web.Services.WebService
{
public Service () {

//如果使用设计的组件,请取消注释以下行
//InitializeComponent();
}

[WebMethod]
public string HelloWorld() {
return "Hello World";
}


错误处理

对 Web 服务的异步调用可能会出现不同的错误,如网络中断、Web 服务不可用或返回异常等。幸运的是,ScriptManager 生成的 JavaScript 代理对象允许定义多个回调,以处理除上面列出的成功调用外的错误和失败。错误回调函数定义可以紧跟在对Web Method 的调用中的标准回调函数之后,如程序列表14 所示。
程序列表14.定义错误回调函数并显示错误

function GetCustomersByCountry()
{
var country = $get("txtCountry").value;
InterfaceTraining.CustomersService.GetCustomersByCountry(country,
OnWSRequestComplete, OnWSRequestFailed);
}

function OnWSRequestFailed(error)
{
alert("Stack Trace: " + error.get_stackTrace() + "/r/n" +
"Error: " + error.get_message() + "/r/n" +
"Status Code: " + error.get_statusCode() + "/r/n" +
"Exception Type: " + error.get_exceptionType() + "/r/n" +
"Timed Out: " + error.get_timedOut());
}


任何在调用 Web 服务发生的错误都将引发调用OnWSRequestFailed()回调函数,接受将错误表示为一个参数的对象。错误对象将显示几个不同的函数,以确定错误的原因以及调用是否超时。程序列表14 是一个使用不同错误函数的示例,图2 演示了函数生成的输出。





[b]图2:调用 ASP.NET AJAX 错误函数产生的输出。[/b]

处理 Web 服务返回的 XML 数据

前面学习了 Web Method 如何使用 ScriptMethod 属性及其ResponseFormat属性返回原始XML 数据。将ResponseFormat设为ResponseFormat.Xml时,从Web 服务返回的数据将被序列化为XML 而非JSON 格式。这在 XML 数据需要直接传递到客户端、以便使用JavaScript 或 XSLT 处理时比较有用。当前,Internet Explorer 5 及更高版本内含对 MSXML 的支持,从而提供了最佳的客户端侧对象模型,用于解析和筛选XML 数据。
从 Web 服务检索 XML 数据与检索其他数据类型一样。首先调用JavaScript 代理以便调用适当的函数并定义回调函数。调用返回后,便可在回调函数中处理数据。
程序列表 15 中的示例是调用一个名为GetRssFeed()、返回一个XmlElement 对象的Web Method。GetRssFeed() 接受一个参数,该参数表示要检索的 RSS 信源的URL。
程序列表15.处理从Web服务返回的 XML数据
function GetRss()
{
InterfaceTraining.DemoService.GetRssFeed(
"http://blogs.interfacett.com/dan-wahlins-blog/rss.xml",
OnWSRequestComplete);
}

function OnWSRequestComplete(result)
{
if (document.all) //Filter for IE DOM since other browsers are limited
{
var items = result.selectNodes("//item");
for (var i=0;i<items.length;i++)
{
var title = items[i].selectSingleNode("title").text;
var href = items[i].selectSingleNode("link").text;
$get("divOutput").innerHTML +=
"<a href='" + href + "'>" + title + "</a><br/>";
}
}
else
{
$get("divOutput").innerHTML = "RSS only available in IE5+";
}
}


本示例传递了一个 RSS 信源的 URL,并在OnWSRequestComplete()函数中处理 XML 数据。OnWSRequestComplete()首先检查使用的浏览器是否为Internet Explorer,以便了解 MSXML 解析器是否可用。如果是,将使用一个XPath 语句来定位 RSS 信源中的所有 <item> 标记。然后每个条目都被遍历一遍,相关联的<title> 和 <link> 标记被定位并处理以便显示每个条目的数据。图3 演示了通过一个 JavaScript 代理向 GetRssFeed() Web Method 发起 ASP.NET AJAX 调用产生的输出

处理复杂类型

Web服务接受或返回的复杂类型是通过JavaScript代理显示的。但如果要直接在客户端侧使用嵌套复杂类型,就必须首先将GenerateScriptType 属性应用于服务,如前面的内容所述。但为什么不直接在客户端侧使用一个嵌套的复杂类型呢?
为了回答这个问题,我们假定有一个 ASP.NET AJAX 页面显示客户数据并允许终端用户更新客户的地址。如果Web 服务指定可以发送 Address 类型(CustomerDetails 类中定义的一个复杂类型)到客户端,那么更新过程可以分为几个独立的函数以便更好地重用代码。



图3:通过调用返回 RSS 数据的 Web 服务创建的输出。
程序列表 16 的客户端侧代码调用了一个在Model 命名空间中定义的Address 对象,用更新后的数据填充它并将它指定到一个CustomerDetails对象的 Address 属性。随后,CustomerDetails 对象被传递给 Web 服务进行处理。
程序列表16.使用嵌套的复杂类型
function UpdateAddress()
{
var cust = new Model.CustomerDetails();
cust.CustomerID = $get("hidCustomerID").value;
cust.Address = CreateAddress();

InterfaceTraining.DemoService.UpdateAddress(cust,OnWSUpdateComplete);
}

function CreateAddress()
{
var addr = new Model.Address();
addr.Street = $get("txtStreet").value;
addr.City = $get("txtCity").value;
addr.State = $get("txtState").value;
return addr;
}

function OnWSUpdateComplete(result)
{
alert("Update " + ((result)?"succeeded":"failed")+ "!");
}


创建和使用页面方法

Web服务提供了一种极好的方法来将可重用的服务提供给大量客户端,包括 ASP.NET AJAX 页面。但有时可能页面需要检索永不会被其他页面使用或共享的数据。在这种情况下,创建一个.asmx 文件来允许页面访问数据似乎有些小题大做了,因为服务只需要为一个页面所用。
ASP.NET AJAX 提供了另外一种方法来发起类似Web服务的调用而无需创建独立的.asmx 文件。这种方法被叫做“页面方法”。页面方法是直接嵌入页面或内含代码的静态(在VB.NET中共享)方法,应用了 WebMethod 属性。通过应用 WebMethod 属性,页面方法可以被名为PageMethods 的特定 JavaScript 对象所调用,这些对象是在运行时动态创建的。PageMethods 对象作为一个代理将您从JSON 序列化/反序列化过程屏蔽。注意,要使用PageMethods 对象,必须将 ScriptManager 的 EnablePageMethods 属性设为 true。
<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="true">
</asp:ScriptManager>
[/code]程序列表 17 中的示例是在一个 ASP.NET 内含代码类中定义两个页面方法。这些方法从网站的App_Code 文件夹中的一个业务层类检索数据。
程序列表17.定义页面方法
[WebMethod]
public static Customer[] GetCustomersByCountry(string country)
{
return Biz.BAL.GetCustomersByCountry(country);
}

[WebMethod]
public static Customer[] GetCustomersByID(string id)
{
return Biz.BAL.GetCustomersByID(id);
}


ScriptManager 检测到页面中有 Web 方法时,将生成一个指向前面提到的PageMethods 对象的动态引用。调用 Web Method 是通过引用 PageMethods 类来实现的。PageMethods 类后面跟的是方法的名称以及任何需要传递的参数。程序列表18 中的示例是调用前面展示的两个页面方法。
程序列表18.用PageMethods JavaScript对象调用页面方法
function GetCustomerByCountry()
{
var country = $get("txtCountry").value;
PageMethods.GetCustomersByCountry(country, OnWSRequestComplete);
}

function GetCustomerByID()
{
var custID = $get("txtCustomerID").value;
PageMethods.GetCustomersByID(custID, OnWSRequestComplete);
}

function OnWSRequestComplete(results)
{
var searchResults = $get("searchResults");
searchResults.control.set_data(results);
if (results != null) GetMap(results[0].Country,results);
}

补充:

using System.Web.Services;
public partial class Default2 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{

}
/// <summary>
/// WebService 创建和使用页面方法
/// </summary>
/// <returns></returns>
[WebMethod]
public static string HelloWorld()
{
return "Hello World";
}
}


<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>无标题页</title>
<script type="text/javascript">
function HelloWorld()
{
PageMethods.HelloWorld(onSuccess);
}
function onSuccess(a)
{
window.alert(a);
}
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="true">

</asp:ScriptManager>
<input type="button" value="button"  onclick="HelloWorld()"/>
</div>
</form>
</body>
</html>


PageMethods 对象的使用与 JavaScript 代理对象的使用非常相似。首先指定应传递给页面方法的所有参数数据,然后定义应在异步调用返回时调用的回调函数。也可指定回调失败(参见程序列表14 的失败处理示例)。

AutoCompleteExtender及 ASP.NET AJAX 工具箱

ASP.NET AJAX 工具箱(可从 http://ajax.asp.net 获取)提供了多种可用于访问Web 服务的控件。具体地说,工具箱包含一个名为AutoCompleteExtender 的有用控件,可用于调用Web 服务并在页面中显示数据而无需编写任何JavaScript 代码。
AutoCompleteExtender控件可用于扩展文本框的现有功能,并帮助用户更轻松地定位到要查找的数据。通过在文本框中输入内容,用户可使用此控件查询Web 服务并在文本框下方动态显示结果。图4 中的示例是使用 AutoCompleteExtender 控件为一个支持应用程序显示客户id。当用户在文本框中输入不同字符时,下方将根据输入内容显示不同条目。然后用户便可以从中选择所需的客户id。
在 ASP.NET AJAX 页面中使用AutoCompleteExtender,要求在网站的 bin 文件夹中添加AjaxControlToolkit.dll程序集。一旦添加了工具箱程序集,您将需要在web.config 中引用它,以便它包含的控件可供应用程序中的所有页面使用。在web.config 的 <controls> 标记中添加如下标记即可:
<add namespace="AjaxControlToolkit" assembly="AjaxControlToolkit" tagPrefix="ajaxToolkit"/>

如果您只需要在特定页面中使用控件,可以通过在页面顶端添加Reference 指示符来引用(如下所示),而非更新web.config:
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit"
TagPrefix="ajaxToolkit" %>
[/code]


图4:使用AutoCompleteExtender控件。
一旦配置了网站以使用 ASP.NET AJAX 工具箱,就可以向页面添加一个AutoCompleteExtender控件,其方式与添加常规ASP.NET 服务器控件非常相似。程序列表19 中的示例是使用控件调用Web 服务。
程序列表19.使用ASP.NET AJAX工具箱AutoCompleteExtender控件
<ajaxToolkit:AutoCompleteExtender ID="extTxtCustomerID" runat="server"
MinimumPrefixLength="1" ServiceMethod="GetCustomerIDs"
ServicePath="~/CustomersService.asmx"
TargetControlID="txtCustomerID" />
[/code]AutoCompleteExtender有几个不同的属性,包括服务器控件上的 standard ID 和runat 属性。除了这些属性外,此控件还可用于定义在向Web 服务查询数据之前终端用户可输入的字符数。程序列表19 中的MinimumPrefixLength 属性使得每向文本框中输入一个字符就调用一次服务。要谨慎设置此属性值,因为每次用户输入一个字符,都将调用Web 服务以搜索与文本框内字符匹配的值。要调用的Web 服务和目标 Web 方法是分别使用 ServicePath 和 ServiceMethod 属性定义的。最后,TargetControlID 属性识别要将 AutoCompleteExtender 控件与哪个文本框挂钩。
调用的 Web 服务必须象前面内容描述的那样应用了 ScriptService 属性,且目标Web 方法必须接受名为prefixText 和count 的两个属性。prefixText 参数表示终端用户输入的字符,而count 参数表示要返回条目的数量(默认为10)。程序列表 20 中的示例是程序列表 19 中的 AutoCompleteExtender控件调用的GetCustomerIDs Web服务。Web 方法调用一个业务层方法,后者又调用一个处理数据筛选并返回匹配结果的数据层方法。数据层方法的代码如程序列表21 所示。
程序列表20.从AutoCompleteExtender控件发出的筛选数据
[WebMethod]
public string[] GetCustomerIDs(string prefixText, int count)
{
return Biz.BAL.GetCustomerIDs(prefixText, count);
}

程序列表21.基于终端用户输入的筛选结果

public static string[] GetCustomerIDs(string prefixText, int count)
{
//Customer IDs cached in _CustomerIDs field to improve performance
if (_CustomerIDs == null)
{
List<string> ids = new List<string>();
//SQL text used for simplicity...recommend using sprocs
string sql = "SELECT CustomerID FROM Customers";
DbConnection conn = GetDBConnection();
conn.Open();
DbCommand cmd = conn.CreateCommand();
cmd.CommandText = sql;
DbDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
ids.Add(reader["CustomerID"].ToString());
}
reader.Close();
conn.Close();
_CustomerIDs = ids.ToArray();
}
int index = Array.BinarySearch(_CustomerIDs, prefixText,
new CaseInsensitiveComparer());
//~ is bitwise complement (reverse each bit)
if (index < 0) index = ~index;
int matchingCount;
for (matchingCount = 0; matchingCount < count && index + matchingCount
< _CustomerIDs.Length; matchingCount++)
{
if (!_CustomerIDs[index + matchingCount].StartsWith(prefixText,
StringComparison.CurrentCultureIgnoreCase))
{
break;
}
}

String[] returnValue = new string[matchingCount];
if (matchingCount > 0)
{
Array.Copy(_CustomerIDs, index, returnValue, 0, matchingCount);
}
return returnValue;
}


补充:
aspx

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>无标题页</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<ajaxToolkit:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
</ajaxToolkit:ToolkitScriptManager>
<ajaxToolkit:AutoCompleteExtender ID="AutoCompleteExtender1" runat="server" MinimumPrefixLength="1"
ServiceMethod="HelloWorld" ServicePath="Service.asmx" TargetControlID="txt" CompletionSetCount="1">
</ajaxToolkit:AutoCompleteExtender>
<asp:TextBox ID="txt" runat="server"></asp:TextBox>
</div>
</form>
</body>
</html>

Service.asmx

public class Service : System.Web.Services.WebService
{
public Service () {

//如果使用设计的组件,请取消注释以下行
//InitializeComponent();
}

[WebMethod]
public string[] HelloWorld() {
return new string[] {"Hello World"};
}

}
PS: Web服务应返还数组类型的返回值,如果返回字符串AutoCompleteExtender控件,会将其打散成一个字符数组

小结

ASP.NET AJAX 为调用 Web 服务以便处理请求和响应消息、而无需编写大量定制 JavaScript 代码提供了极佳的支持。本文档介绍了如何为.NET Web 服务启用 AJAX,以使它们能处理 JSON 消息,以及如何使用 ScriptManager 控件定义JavaScript 代理。此外我们还学习了如何使用JavaScript 代理调用 Web 服务、处理简单和复杂类型以及处理失败操作。最后,我们还学习了如何使用页面方法简化创建和发起Web 服务调用,以及 AutoCompleteExtender 控件如何为终端用户进行输入时提供帮助。尽管ASP.NET AJAX 中可用的UpdatePanel 将因其简洁性最终成为许多AJAX 程序员的选择,但了解如何通过JavaScript 代理调用 Web 服务在许多应用程序中也是有用的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: