11.9如何使用JavaScript调用远程Web服务
在此之前的页面范例都是调用我们自行编写的Web服务,然而在浩瀚的因特网世界中,有许多网络提供商提供了非常多功能丰富的Web服务,不论这些Web服务是免费的不是付费的,如何使用JavaScript去调用这些远程Web服务是一项非常重要的课题。
幸运的是,调用外部网络提供商所建构的Web服务在作法上并没有什么差异。需要注意的是,如果将远程的Web服务功能纳入本身的应用程序中,必须考虑网络响应速度的快慢,此外,由于服务内容与功能受制于开发Web服务的提供商,所以通常不建议将关键性的数据交换与逻辑处理放在Web服务来作为应用程序的核心。
页面范例 - 实现RSS订阅器
如图11-34与图11-35所示,页面范例CH11_ DemoForm012.aspx示范如何调用微软所提供的RSS服务,返回微软针对软件产品所发行的知识库文章标题与说明。由于RSS服务具备实时性效果,当微软公布新的知识库文章时,通过RSS服务可取得最新的文章标题与内容,客户端只需要再次调用远程的服务返回结果即可,页面设计技巧与重点说明如下:
·如图11-36所示,在页面上添加一个Xml DataSource对象,并设置其DataFile属性,代表我们将使用服务器上的Xml文档数据当作下拉列表的内容元素。当作数据源的Xml文件位于Xml文件夹内的Microsoft Products.xml中,其中的每一笔项目以Name属性表示产品的名称,Value属性代表连接至知识库文章的网址,列举出当前微软所提供产品与发布知识库文章的RSS连接。Xml文件内容摘要如下:
·为页面上用来显示产品列表的DropDownList控件进行下列设置:
◇ 将DataSourceID属性设置为XmlDataSource1,表示下拉列表的内容元素来自于Xml文件内容。
◇ 将AutoPostBack属性设置为True,当用户选择不同元素之后,页面将重新加载新的内容。
◇ 将DataTextField属性设置为Name,以便将下拉列表的显示文字绑定到数据源的Name属性。
◇ 将DataValueField属性设置为Value,以便将列表的元素值绑定到数据源的Value属性。
◇ 其实在许多时候,我们会希望页面上的DropDownList控件同时拥有数据源元素与自定义元素。以本页面范例用于选择产品的DropDownList控件而言,第一个选项“请选择欲取得RSS的产品名称”显然是一个自定义元素,而其他选项则是来自XML文件的每一笔数据的Name属性(如图11-37所示)。
要完成这样的设置,请先将DropDownList控件的AppendDataBoundItems属性设置成True。接下来在“属性”窗口中单击Items属性右侧的“…”按钮。“ListItem集合编辑器”对话框开启后,单击“添加”按钮,并如图11-38所示设置相关设置,最后再单击“确定”按钮即可。
在此要特别提醒大家,您可以添加多个自定义元素,欲添加多个自定义元素,请反复前述的操作,直到您已经添加所需的多个自定义元素为止。
·请为DropDownList控件的SelectedIndexChanged事件处理函数编写下列程序代码,以便当用户选择不同的列表选项时更改配置文档Web.config的应用程序设置值,也就是下拉列表元素所代表的RSS连接位置:
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e) { if (WebConfigurationManager.AppSettings.Get("MicrosoftRssUrl").ToString() == String.Empty) { WebConfigurationManager.AppSettings.Set("MicrosoftRssUrl", "http://support.microsoft.com/common/rss.aspx?rssid=1265"); } else { WebConfigurationManager.AppSettings.Set("MicrosoftRssUrl", this.DropDownList1.SelectedValue); } } End Sub |
·页面上的“取得RSS”按钮是一个HTML按钮,如下所示,我们设置当按下此按钮时就执行JavaScript函数bntGetRSS_onclick():
<input id="btnGetRSS" type="button" value="取得RSS" onclick="btnGetRSS_onclick();" /> |
• JavaScript函数bntGetRSS_onclick() 编写于JS文件夹内的JS_RSS.js中,其程序代码如下所列:
// JS_RSS.js function btnGetRSS_onclick() { // 调用Web 服务WS_RSS_Header 的RequestRSS 方法来取得表头。 WS_RSS_Header.RequestRSS(onComplete, OnError, "RssXmlHeader"); // 调用Web 服务WS_RSS_Details 的RequestRSS 方法来取得细部元素内容。 WS_RSS_Details.RequestRSS(onComplete, OnError, "RssXmlDetails"); } |
• 从以上的程序代码可以看出,成功调用不同的Web服务之后,都是交给同一个成功回调函数
来处理,以便承接Web服务所返回的Xml内容,然后加以解析、编排之后呈现在画面上。问题
是,成功回调函数必须判断是哪一个Web服务所掷回的结果。作法很简单,就是利用第三个
参数来判断, 而这个参数也称之为用户自定义内容( User Context)。成功回调函数
onComplete的程序代码如下:
// 成功回调函数。 function onComplete(result, userContext) { if(userContext == "RssXmlHeader") { $get('result').style.display = "block"; // 标题内容。 $get('HeaderTitle').innerHTML = result[0].HeaderTitle; $get('HeaderLink').innerHTML = result[0].HeaderLink; $get('HeaderDescription').innerHTML = result[0].HeaderDescription; } else if(userContext == "RssXmlDetails") { // 利用循环依序将数据取出。 var resultContent = ""; var i; resultContent += "<table class='table'><thead><tr><td><nobr>编号</nobr> </td><td>细项标题</td><td>细项内容</td><td> <nobr>细项描述</nobr></td></thead></tr>"; for(i=0;i<result.length;i++) { var k = i + 1; if(i%2 == 0) { resultContent += "<tr class='tr1'>"; } else { resultContent += "<tr class='tr2'>"; } resultContent += "<td>" + k + "</td>" + "<td>" + result[i].Title + "</td>" + "<td><a href='" + result[i].Link + "' target='_blank'>" + result[i].Link + "</a></td>"; if(result[i].Description.length == 0) { resultContent += "<td>" + " " + "</td></tr>"; } else { resultContent += "<td>" + result[i].Description + "</td></tr>"; } } resultContent += "</table>"; $get('Detail').innerHTML = resultContent; } else if(userContext == "RssServerTime") { $get('ServerTime').innerHTML = "现在服务器时间为:" + result; } } |
• 由于RSS服务所返回的内容包括表头与细部内容两个部分,所以分别使用了两个不同的Web服
务方法来处理表头数据与细部元素内容。JavaScript会调用Web服务WS_RSS_Header.asmx的
RequestRSS方法来处理表头数据,并将结果返回给客户端。Web服务WS_RSS_Header.asmx的
程序代码如下:
... ... [WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] [ScriptService()] public class WS_RSS_Header : System.Web.Services.WebService { ... [WebMethod] public object RequestRSS() { // 读取Web.config 配置文档设置。 Uri RssUrl = new Uri( WebConfigurationManager.AppSettings.Get("MicrosoftRssUrl").ToString()); if (RssUrl.Scheme == Uri.UriSchemeHttp) { // 创建HttpWebRequest 类对象来发出HTTP 请求。 HttpWebRequest RssRequest = (HttpWebRequest)(HttpWebRequest.Create(RssUrl)); RssRequest.Method = WebRequestMethods.Http.Get; // 创建HttpWebResponse 类对象来接受HTTP 响应。 HttpWebResponse RssResponse = (HttpWebResponse)(RssRequest.GetResponse()); // 创建代表HTTP 响应的StreamReader 串流对象。 StreamReader RssReader = new StreamReader(RssResponse.GetResponseStream()); // 将HTTP 响应(也就是Xml 文件内容)写入一个字符串。 string RssResult = RssReader.ReadToEnd(); // 创建XPathBridgeTransformer 类对象来转换Xml 内容。 XPathBridgeTransformer RssTransformer = new XPathBridgeTransformer(); // 创建BridgeTransformData 类对象存储转换Xml 信息。 BridgeTransformData RssData = new BridgeTransformData(); // 设置Xml 转换准则,也就是筛选Xml 文件的条件。 RssData.Attributes.Add("selector", "channel"); // 创建Dictionary 对象,存储筛选后的Xml 内容。 Dictionary<string, string> RssDictionary = new Dictionary<string, string>(3); // 添加Dictionary 对象内容,键值(Key)代表前端JavaScript 编写脚本使用的名称, // 数值(Value)代表Xml 文件标签。 RssDictionary.Add("HeaderTitle", "title"); RssDictionary.Add("HeaderLink", "link"); RssDictionary.Add("HeaderDescription", "description"); // 将Dictionary 对象添加BridgeTransformData 类对象。 RssData.Dictionaries.Add("selectedNodes", RssDictionary); // 初始化创建XPathBridgeTransformer 类对象,预备进行Xml 数据转换。 RssTransformer.Initialize(RssData); // 正式进行Xml 文件转换,并将结果返回前台。 return RssTransformer.Transform(RssResult); } return null; } } • JavaScript紧接着会调用Web服务WS_RSS_Details.asmx的RequestRSS方法来处理细部元素内 容,并将结果返回给客户端。Web服务WS_RSS_Details.asmx的程序代码如下: ... ... [WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] [ScriptService()] public class WS_RSS_Details : System.Web.Services.WebService { ... [WebMethod] [ScriptMethod(UseHttpGet=true)] public object RequestRSS() { // 读取Web.config 配置文档设置。 Uri RssUrl = new Uri( WebConfigurationManager.AppSettings.Get("MicrosoftRssUrl").ToString()); if (RssUrl.Scheme == Uri.UriSchemeHttp) { // 创建HttpWebRequest 类对象来发出Http 请求。 HttpWebRequest RssRequest = (HttpWebRequest)(HttpWebRequest.Create(RssUrl)); RssRequest.Method = WebRequestMethods.Http.Get; // 创建HttpWebResponse 类对象来接受Http 响应。 HttpWebResponse RssResponse = (HttpWebResponse)(RssRequest.GetResponse()); // 创建代表HTTP 响应的StreamReader 串流对象。 StreamReader RssReader = new StreamReader(RssResponse.GetResponseStream()); // 将HTTP 响应(也就是Xml 文件内容)写入一个字符串。 string RssResult = RssReader.ReadToEnd(); // 创建XPathBridgeTransformer 类对象来转换Xml 内容。 XPathBridgeTransformer RssTransformer = new XPathBridgeTransformer(); // 创建BridgeTransformData 类对象存储转换Xml 信息。 BridgeTransformData RssData = new BridgeTransformData(); // 设置Xml 转换准则,也就是筛选Xml 文件的条件。 RssData.Attributes.Add("selector", "channel/item"); // 创建Dictionary 对象,存储筛选后的Xml 内容。 Dictionary<string, string> RssDictionary = new Dictionary<string, string>(3); // 添加Dictionary 对象内容,键值(Key)代表前端JavaScript 编写脚本使用的名称, // 数值(Value)代表Xml 文件标签。 RssDictionary.Add("Title", "title"); RssDictionary.Add("Link", "link"); RssDictionary.Add("Description", "description"); // 将Dictionary 对象添加BridgeTransformData 类对象。 RssData.Dictionaries.Add("selectedNodes", RssDictionary); // 初始化创建XPathBridgeTransformer 类对象,预备进行Xml 数据转换。 RssTransformer.Initialize(RssData); // 正式进行Xml 文件转换,并将结果返回前台。 return RssTransformer.Transform(RssResult); } return null; } }
|
【责任编辑:
夏书 TEL:(010)68476606】