摘要 为了从Atlas中消费外部Web服务,你可以为这些服务构建一个基于服务器的Web服务代理。幸好,你可以利用Visual Studio和Atlas特征来处理这其中的大部分工作。
  
  一、引言

  如今,AJAX已 经成为构建基于浏览器的交互式客户端应用程序的主流技术,从而使得服务器端行为集中于提供特定的Web服务。另一方面,Web服务已经成为当今在服务器级 暴露业务功能的事实上的标准。假定如此,那么出现一个核心开发问题:如何使你的基于AJAX的应用程序与Web服务进行通讯?本文正是想同你一起探讨如何 使用微软Atlas(最近,又命名为ASP.NET AJAX)来实现这一目的。

  首先,你需要使用Visual Studio 2005,并且需要下载和安装微软Atlas。如果你没有安装Visual Studio 2005,那么你可以下载一个免费的Visual Studio Express版本。本文将使用一个ZipCodeRUs示例应用程序来解释如何通过Atlas实现该程序与Web服务的交互。这个示例应用程序能够检索 详细的邮政代码信息,例如城市、县的名称及其纬度、经度等信息。该程序依赖于tilisoft.com网站提供的一个免费且公开可用的Web服务来检索该 信息。这个示例应用程序从下面两个角度展示了Atlas的Web服务威力:

  · 展示了Atlas的JavaScript代理,这个代理能够与一个ASP.NET(.asmx)Web服务(该服务担当到外部Tilisoft ZIP代码Web服务的"沟通"桥梁)进行异步地通讯。

  · 还展示Atlas从JavaScript客户端成批地调用服务器端web服务的能力。

  【作者注】 微软Atlas还支持创建到外部Web服务的基于XML的声明性桥接而不必创建上面的所谓"沟通"服务;不过,本文并没有涉及有关这个桥接特征的讨论。

  二、Atlas Web服务入门

   打开Visual Studio,通过选择如图1所示的"Atlas"Web Site模板创建一个新的Web应用程序"ZipCodeRUs"。该"Atlas"Web Site模板是当你下载并安装微软Atlas CTP时安装的。基于这个"Atlas"Web Site模板创建的网站中会自动包含对Microsoft.Web.Atlas.dll的一个引用;还包括一个Web.config文件,该文件为网站使 用Atlas技术作好了预配置。


图1.创建一个新的Atlas Web应用程序:当你安装微软Atlas CTP后,你会在"New Web Site"对话框中看到一个新的称为"Atlas"Web Site的工程模板。

   与依赖于外部Web服务(服务不是在与应用程序本身相同的域内提供)的AJAX应用程序相关的一个常见的问题是,你不能够使用JavaScript来直 接存取这样的Web服务-浏览器将阻止所有这样的"cross-scripting"存取。由于安全原因,浏览器仅仅允许一个Web页面中的 JavaScript存取最初创建该页面的网站。为了解决这个问题,Atlas JavaScript客户端依赖于.asmx文件(ASP.NET Web服务)来创建运行时刻JavaScript代理。换句话说,客户端先调用一个由home(本地)域所暴露的Web服务,然后由这个服务再调用外部 Web服务,最后简单地把响应传送回客户端。

  因此,在你能够从你的Atlas客户端调用一个外部Web服务前,你首先需要创建一个强类型化代理。在这个示例中,我为Zip代码Web服务构建了一个C#代理,其中还创建了一个ASP.NET Web服务,它用作一个上面的"沟通桥梁"。

  三、 创建一个代理客户类

   存在两种创建Web服务客户端代理类的方法。你可以在Visual Studio命令行上使用wsdl.exe来创建这些代理类;或者从Visual Studio IDE中创建一个Web引用。下面命令展示了如何从你的应用程序的App_Code文件夹下使用wsdl.exe来为ZipCode Web服务创建强类型化代理类。注意,当你从命令行输入下列代码时,下面这些内容应该在同一行上。

C:\projects\ZipCodeRUS\App_code> wsdl.exe 
[url]http://www.tilisoft.com/ws/LocInfo/ZipCode.asmx?WSDL[/url] 
/namespace:Tilisoft.ZipCode

  上面的命令将创建一个ZipCode.cs文件,它包含一个你能够在你的本地的代码中使用的TiliSoft.ZipCode代理类。

  接下来,你需要创建上面起"沟通桥梁"作用的Web服务。右击Solution Explorer中的最上面一层,并从弹出菜单中选择"Add New Item…"选项,然后选择Web服务模板。我把该服务命名为"ZipCodeConduitService"。

   这个ZipCodeConduitService服务中只提供了一个称为GetZipCodeInfo的函数。它使用两个字符串参数:一个字符串 correlationID,一个ZIP代码。当被调用时,该服务使用生成的代理类以便TiliSoft Web服务检索特定数据,最后,把这些结果传递回ZipCodeConduitData应用程序。为了演示Atlas的异常处理能力,我添加了一个"小拐 弯":如果用户输入的ZIP代码是"错误",那么GetZipCodeInfo()将抛出一个ZipCodeConduitException异常。下面 是相应于ZipCodeConduitService Web服务类的代码:

...
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class ZipCodeConduitService : System.Web.Services.WebService{ 
...
[WebMethod]
public ZipCodeConduitData GetZipCodeInfo(String corelationId,String zipCode) {
if (zipCode.Equals("error")){
throw new ZipCodeConduitException(corelationId,"Here is an error just for you!! Enjoy!");
}
ZipCode xZipCodeService = new ZipCode();
ZipCodeConduitData zipCodeConduitData = null;
ZipCodeData xZipCodeData = xZipCodeService.GetInfo(zipCode);
zipCodeConduitData = new ZipCodeConduitData(corelationId, zipCode, xZipCodeData);
return zipCodeConduitData;
}
}

   在前面的代码中,ZipCodeConduitData是一个值对象,用于在客户端和ZipCodeConduitService之间传递信息。这个 ZipCodeConduitData类具有如下所示的get属性,而CorelationId属性允许客户端跟踪它们的请求。

...
using Tilisoft.ZipCode;
public class ZipCodeConduitData{
public ZipCodeConduitData(String corelationId,ZipCodeData data) {
hydrate(corelationId, data);
}
String _corelationId;
public String CorelationId{
get { return _corelationId; }
}
...
String _county;
public String County{
get { return _county; }
}
String _city;
public String City{
get { return _city; }
}
...
private void hydrate(String corelationId, ZipCodeData data) {
_corelationId = corelationId;
if (data.ZipCodeInfo.Count > 0) {
_zipCode = data.ZipCodeInfo[0].ZIPCODE;
_county = data.ZipCodeInfo[0].COUNTY;
_city = data.ZipCodeInfo[0].CITY;
...
}
}
}

  这个ZipCodeConduitException是一个派生自System.Exception的C#异常类。该异常类包括correlationId值;客户端在每次发送请求时都使用它,详见下面的代码片断:

...
using System;
...
public class ZipCodeConduitException : System.Exception{
 String _corelationId;
 public String CorelationId{
  get { return _corelationId; }
  set { _corelationId = value; }
 }
 public ZipCodeConduitException(String corelationId, String message):base(message) {
  _corelationId = corelationId;
 }
}
  四、 构建ZipCode JavaScript客户端

  现在,既然你已经实现了服务器端的Web服务代码,那么接 下来,你可以创建一个存取该服务的JavaScript客户端。为此,你要添加ZipCodeConduitClient.aspx;这是通过使用 "Add New Item…"→"Web Form"选项来把一个Web表单添加到你的ZipCodeRUs中实现的。

  在 ZipCodeConduitClient.aspx代码中,通过创建Atlas的ScriptManager的一个实例并且把一个对基于ASP.NET 的Web服务ZipCodeConduitService.asmx文件的引用添加到Web页面的元素来启动微软Atlas。详见下面的代码:

...
<head id="Head1" runat="server">
<title>Zip Code Information Service - Atlas JavaScript Conduit 
Client</title>
<atlas:ScriptManager ID="scriptManager" runat="server" 
EnableScriptComponents="true">
<Services>
<atlas:ServiceReference 
Path="ZipCodeConduitService.asmx" />
</Services>
</atlas:ScriptManager>
<script type="text/xml-script">
<page xmlns:script=
"http://schemas.microsoft.com/xml-script/2005">
<components>
<webRequestManager batchSize="5" 
enableBatching="true" batchDelay="3000" />
</components>
</page>
</script>
</head>
...

   有趣的是,前面的代码支持在JavaScript和Web服务之间的"批"方式的Web服务请求。通过添加webRequestManager元素以及 把enableBatching属性值设置为true可以使得由Atlas来承担所有的繁重工作-积累所有的请求,然后在一个批中立即执行它们。 Atlas还能够跟踪所有的返回值和来自于Web服务中的对象。注意,上面的代码能够"积累"达到五个请求,然后一次性执行所有的请求。

  现在,你可以通过添加一些HTML和ASP元素来创建web页面上的可视化元素。最终产生的页面大致如图2所示。


图2.该图展示了Visual Studio中处于设计方式的ZipCodeConduitClient.aspx页面。

...
<form id="ZipCodeConduitClient" runat="server" ></form>
<h4>
Enter ZipCodes: 1> <input id="textZipCode1" />
2> <input id="textZipCode2" />
3> <input id="textZipCode3" />
<input id="buttonZipCode" type="button" 
value="Get Information" 
OnbuttonZipCode_click()" />
</h4>

<table border="1" cellpadding="5" cellspacing="2">
<tr>
<td></td>
<td><asp:Label ID="corelationId1" runat="server" 
Text="."/></td>
<td><asp:Label ID="corelationId2" runat="server" 
Text="."/></td>
<td><asp:Label ID="corelationId3" runat="server" 
Text="."/></td>
</tr>
<tr>
<td>ZipCode</td>
<td><asp:Label ID="zipCode1" runat="server" 
Text="."/></td>
<td><asp:Label ID="zipCode2" runat="server" 
Text="."/></td>
<td><asp:Label ID="zipCode3" runat="server" 
Text="."/></td>
</tr>
... 
<tr>
<td></td>
<td><asp:Label id="message1" runat="server" 
Text="."/></td>
<td><asp:Label id="message2" runat="server" 
Text="."/></td>
<td><asp:Label id="message3" runat="server" Text="."/></td>
</tr>
</table>
<br />

<asp:Label ID="message" runat="server" BorderStyle="Groove" 
BackColor="#FF8080" BorderWidth="1px" Font-Bold="True" 
ForeColor="White">Ready</asp:Label>
...

  注意,在此,"Get Information"(在源代码中命名为buttonZipCode)按钮的点击导致调用OnbuttonZipCode_click() JavaScript函数,请参考下面的代码:

<script type="text/javascript" language="JavaScript"> 
function OnbuttonZipCode_click() 
{
document.getElementById('message').innerHTML = "Retrieving Information...";
if (document.getElementById('textZipCode1').value.length > 0)
{
service = ZipCodeConduitService.GetZipCodeInfo("1", document.getElementById('textZipCode1').value, 
OnComplete, //完成事件
OnTimeout, //超时事件
OnError // 出错事件
); 

...
}
return false;

...
</script>

   在这个OnbuttonZipCode_click函数中,ZipCodeConduitService JavaScript代理对象可以为Atlas所隐含地使用。注意,GetZipCodeInfo()函数共使用三个参数,除了在 ZipCodeConduitService Web服务中GetZipCodeInfo()函数所使用的两个参数以外。这是因为Atlas使所有的Web服务调用都以异步地进行;在发出一个Web服 务调用后,JavaScript客户端代码并不等待该服务器的响应。当响应到达时,Atlas框架需要使用客户端的一个回调函数。 GetZipCodeInfo方法使用的其它参数正是从JavaScript代码指向这些回调函数的指针。来自于服务器的响应可能是成功的,可能是返回一 个错误消息,也可能是因超时而无响应返回。前面的代码分别由OnComplete(),OnError()和OnTimeout()函数负责处理每一种可 能的响应类型。
 下面代码列出了这些函数。这些函数都接收一个result参数,其中包含服务器返回的响应。在此情况下,ZipCodeConduitService把 一个ZipCodeConduitData类的实例返回给OnComplete()函数,而把一个ZipCodeConduitException异常返 回给OnError()函数。

...
function OnComplete(result) {
document.getElementById('message').innerHTML = "Ready";
if (result.CorelationId == '1') {
document.getElementById('corelationId1').innerHTML = result.CorelationId;
...
document.getElementById('message1').innerHTML = 
result.Message;
}
else if (result.CorelationId == '2') {
...
}
else if (result.CorelationId == '3') {
...
}
}
function OnError(result) {
displayMessage(result);
}
function OnTimeout(result) {
document.getElementById('message').innerHTML = "Request Timeout";
}
function displayMessage(result) {
if (result.CorelationId == '1') {
document.getElementById('message1').innerHTML = result.get_message();
}
...
}
</script>

  五、运行结果

  至此,服务器端与客户端代码都已到位。在Visual Studio中以debug方式启动ZipCodeConduitClient.aspx或把你的应用程序发布到一个网站;然后,试着输入三个ZIP代码来检索关于这三个ZIP代码的细节,请参考下面图3。


图3.ZipCodeConduitClient运行中:这是在一个Web浏览器中运行ZipCodeConduitClient.aspx页面并显示检索三个ZIP代码的结果。

  六、小结

   如今,AJAX使得开发交互性的Web应用程序进一步简单化;而现在微软也已经着手简化从支持AJAX技术的客户端应用程序中调用Web服务的过程。随 着AJAX技术进一步融入主流开发中,我们完全可以期望微软把Atlas更为紧密地集成到Visual Studio中及其它微软开发平台和产品中。

本文转自朱先忠老师51CTO博客,原文链接: http://blog.51cto.com/zhuxianzhong/60090,如需转载请自行联系原作者

利用微软Atlas消费外部Web服务相关推荐

  1. 一文讲透推荐系统提供web服务的2种方式

    作者丨gongyouliu 编辑丨zandy 来源 | 大数据与人工智能(ID: ai-big-data) 推荐系统是一种信息过滤技术,通过从用户行为中挖掘用户兴趣偏好,为用户提供个性化的信息,减少用 ...

  2. Spring Boot 构建RESTful Web服务

    Spring Boot 构建RESTful Web服务 本指南将引导您完成使用Spring 创建" Hello World" RESTful Web服务的过程. 你会建立什么 您将 ...

  3. Spring集成和Web服务

    本文是我们名为" Spring Integration for EAI "的学院课程的一部分. 在本课程中,向您介绍了企业应用程序集成模式以及Spring Integration如 ...

  4. SpringBoot调用RESTful Web服务

    SpringBoot调用RESTful Web服务 本指南将引导您完成创建使用RESTful Web服务的应用程序的过程. 你会建立什么 您将RestTemplate在https://gturnqui ...

  5. 消息(5)——WSE增强的web服务套件,MTOM附件

    WSE是什么? 它是Web Service Enhancements,是微软发布的构筑Web服务应用程序的附加套件.这个套件可以使web服务应用程序支持WS-Security.WS-Routing.W ...

  6. 异步调用Web服务方法

    基于Ajax技术构建的门户是web 2.0这一代中最为成功的Web应用程序.而这块市场上iGoogle和Pageflakes这两大站点已经走在了时代的前列. 当你打开Pageflakes,将会看到如下 ...

  7. 通过 Lotus Domino Java 代理消费 Web 服务

    Web 服务是一种允许两台或更多的计算机在网络中交互的系统设计.这种服务的主要优点是,它是在多台不同操作系统的计算机和应用服务器之间发送对象的标准解决方法.例如,我们的公司使用 Web 服务从一台运行 ...

  8. 利用 Celery 构建 Web 服务的后台任务调度模块

    来源:http://www.tuicool.com/articles/Enaeymm 任务队列在 Web 服务里的应用 在 Web2.0 后的时代,社交网站.搜索引擎的的迅猛发展对 Web 服务的后台 ...

  9. jax-rs jax-ws_通过JAX-WS Provider在Web服务中利用MOXy

    jax-rs jax-ws 在以前的文章中,我演示了如何将EclipseLink JAXB(MOXy)直接集成到WebLogic(从12.1.1开始)和GlassFish(从3.1.2开始)的JAX- ...

最新文章

  1. 第二章 单元测试的基本概念和核心技法
  2. Observer模式在J2EE中的实现
  3. 如何当好PM?请求大家积极讨论
  4. 使用 GraalVM 将纯 JavaFX 项目打包成 EXE
  5. php redis 源码分析,从源码中分析关于phpredis中的连接池可持有数目
  6. ES5-7 立即执行函数、闭包深入、逗号运算符
  7. 因特网使用期限_Internet死亡时使用PC的其他方式
  8. c6011取消对null指针的引用_C++| 函数的指针参数如何传递内存?
  9. Codewars-Javascript训练手册:Date 对象
  10. Cocos2d-x schedulers 定时器
  11. 解密javascript模块载入器require.js
  12. 深圳465亿建11代生产线,TCL三星带头认购股权
  13. 企业信息化基本指标构成方案(试行)上
  14. beescms网站渗透测试和修复意见
  15. PLC模拟量控制的3个要求
  16. Word表格中的文字垂直、纵向居中
  17. 提到单片机很多人都很觉得不陌生,大街小巷上面电子产品都用到
  18. 图像检索基于BOF(Bag-Of-Features Models)
  19. AndroidStudio入门基础(一)——基础布局
  20. 详解Python中列表切片及浅拷贝的关系(上)

热门文章

  1. Win8.1下Node.js连接oracle
  2. 矩阵对抗与系统补丁200911(第2期)下载
  3. JAVA通信系列三:Netty入门总结(转)
  4. 区块链技术没那么复杂,别被大佬们忽悠晕了
  5. git提交pull request到主项目
  6. 关于Kotlin语法的异议
  7. POJ1190 生日蛋糕
  8. 我的第一个纯手写jQuery插件
  9. dedecms织梦移站后替换数据库中文件路径命令
  10. HTML5 离线存储之Web SQL