任何在调用 Web 服务发生的错误都将引发调用OnWSRequestFailed()回调函数,接受将错误表示为一个参数的对象。错误对象将显示几个不同的函数,以确定错误的原因以及调用是否超时。程序列表14 是一个使用不同错误函数的示例,图2 演示了函数生成的输出。
图2:调用 ASP.NET AJAX 错误函数产生的输出。
处理 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( "", 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。
程序列表 17 中的示例是在一个 ASP.NET 内含代码类中定义两个页面方法。这些方法从网站的App_Code 文件夹中的一个业务层类检索数据。