新书推介:《语义网技术体系》
作者:瞿裕忠,胡伟,程龚
   XML论坛     W3CHINA.ORG讨论区     >>计算机科学论坛<<     SOAChina论坛     Blog     开放翻译计划     新浪微博  
 
  • 首页
  • 登录
  • 注册
  • 软件下载
  • 资料下载
  • 核心成员
  • 帮助
  •   Add to Google

    >> 最新的技术动态
    [返回] 计算机科学论坛休息区『 最新动态 & 业界新闻 』 → 可靠的 XML Web 服务 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 3219 个阅读者浏览上一篇主题  刷新本主题   树形显示贴子 浏览下一篇主题
     * 贴子主题: 可靠的 XML Web 服务 举报  打印  推荐  IE收藏夹 
       本主题类别:     
     diy930 帅哥哟,离线,有人找我吗?双鱼座1979-3-8
      
      
      威望:4
      头衔:用脑专家
      等级:大三暑假(TOFEL考了650分!)
      文章:50
      积分:930
      门派:XML.ORG.CN
      注册:2004/7/12

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给diy930发送一个短消息 把diy930加入好友 查看diy930的个人资料 搜索diy930在『 最新动态 & 业界新闻 』的所有贴子 引用回复这个贴子 回复这个贴子 查看diy930的博客楼主
    发贴心情 可靠的 XML Web 服务

    Eric Schmidt

    Microsoft Corporation

    2001 年 12 月 11 日

    下载 ericrp.exe。

    注 运行与本文相关的下载文件需要下列内容:

    • Visual Studio .NET Professional

    • SQL Server 2000

    在 PDC 上,我谈论了有关可靠的 XML Web 服务(Web 服务)的话题,这个话题源于过去一年来的多次交流。在有关构建 XML Web 服务的各种常见问题中,可靠性问题是开发人员实现分散式 Web 服务所面临的五个最重要的问题之一。如果分解开来讲,这个问题并不是太难,因此,本月我准备谈一谈构建可靠的 XML Web 服务这一棘手的问题。

    本页内容
    概述
    XML Web 服务的可靠性
    构建可靠性层
    ericRP 的工作原理
    头的作用
    把代码合在一起
    展望

    概述
    全球 XML Web 服务结构 (GXA) 最突出的一面就是可以使用可合成处理协议扩展该结构。这些协议主要通过 SOAP 头实现,可以提供包括安全性、加密、路由和可靠性在内的广泛服务。当您开始构建基于 GXA 的应用程序时,您将发现 GXA 实质上是一种消息处理结构,它通过基于标准的编码技术 (SOAP) 在系统和服务之间提供互操作性。到目前为止,大部分实现工作都集中在符合 SOAP 1.1 和 WSDL 的服务上,因此 Web 服务实现可以与多种语言和操作系统互操作。

    这是一个了不起的概念。任何两个系统之间都能够进行交流,只要它们能够分析 XML 并理解 SOAP 规范的规则。但是,简单的消息交换并不能满足复杂业务应用程序的需要。真正的应用程序(不管其内部域结构如何)均需要标准化的服务,如在 Web 服务消息处理层上公开的安全性、授权和可靠性。在全球 XML Web服务结构(具体地说就是 SOAP、SOAP 模块和基础结构协议)的创建和实现背后有一个巨大的动力。随着过去的十月份四项新规范(WS-Routing、WS-Referral、WS-Licensing 和 WS-Security)的发布,我们已经开始着手下一代 XML Web 服务的实现工作。尽管发布了这么多的新规范,但仍有两个领域尚无公共规范,即事务处理和可靠的消息处理,这主要是因为这些基础结构协议依赖于底层 SOAP 模块。

    本专栏主要从 GXA 环境的角度讨论可靠性和可靠的消息处理的含义。我还要特别花一些时间探讨通过在 .NET 框架中扩展现有 Web 服务类来开发可靠性协议需要做些什么。本专栏有两个主要目的:

    • 让读者了解可靠性概念,为以后各种规范的实施做好准备。切记,本文不是规范,而只是一篇文章,旨在引发读者思考下面要讨论的问题。

    • 说明 .NET 框架中 Web 服务和 SOAP 类强大的、基于标准的功能。

    返回页首
    XML Web 服务的可靠性
    我们把问题分解开来讲。如上所述,GXA 服务的实现是消息服务。它们需要在分散式环境中发送和接收基于标准的编码消息。在 Web 服务实现中发送 SOAP 消息的主要传输协议是 HTTP。HTTP 易于实现和管理,但本身不可靠。我们无需深入探讨 HTTP 不可靠的具体原因,但只要知道 HTTP 没有基于标准的服务来保证终点或服务器能够接收到请求就足够了。尽管内置的网络层设备会在发生一般灾难性故障(例如未找到资源)时产生错误,但是却没有机制可以确保客户端能够以可靠的方式接收请求或响应。

    在以前,是通过简单的重新发送操作来处理 HTTP 故障,但在业务处理环境中,这既没有效率也没有效果。它导致不必要的通讯量,并增加了重复事务处理的风险。

    目前市场上有多种能够更有力地解决此问题的消息处理技术 — 从传输协议(如 HTTPR)到企业基础结构(如 MSMQ 和 MQ Series),再到业务处理协议(如 ebXML)。尽管每种技术针对特定的实现各有优点,但都不能通过可在所有传输协议上的域中应用的可扩展方式解决可靠性问题。而且,在消息交换和处理方面的功能层次上也不尽相同。

    面对所有这些问题,我决定总结一个需求列表,看一看在 Web 服务环境中实现可靠性原型需要做哪些工作。

    以下是对我自己创建的可靠性层的集中式需求列表:

    • 基于标准并应用于消息协议层

    • 确认传送

    • 有序传送

    • 对称对话

    • 加快异步处理

    基于标准
    该协议必须由现有的基于标准的技术组成。具体地说,该协议还应该对 SOAP 1.1 规范进行扩展,然后应用到消息编码层(而非传输层)。这样,消息才能够通过所有可用的机制(从 HTTP 到某些专用套接字实现)传输。

    确认传送
    为了有章可循,该协议必须采用某种确认的传送机制。也就是说,使用该协议发送的消息应当从处理器接收一个且只有一个关于该消息状态的确认信息。

    有序传送
    有序传送引入了对话概念,即客户端和服务器可以交换消息和确认,而且确认是可唯一标识的对话的一部分。收到消息后,对消息进行检查以排序,确保处理器收到一组有序的消息。

    对称对话
    建立在对话机制之上,还必须小心谨慎,确保消息和确认的对称性。必须确保每条消息只被处理一次,并且只生成一个确认。

    加快异步处理
    这是需求列表中最重要的一点,所以留在最后说明。HTTP 基于同步请求响应模型。它适用于处理任务量小或运行时间短的简单应用程序。Web 服务实现有一个隐晦的小秘密,即用户不需要从处理的角度了解服务是如何在后端实现的。也就是说,Web 服务实现处理一个请求可能只需要三秒钟,也可能会花上三个小时。这导致消息处理结构效率低下,且无法进行伸缩。我们需要的是一个能够加快异步消息处理结构的处理模型。但是要注意,异步模型实现要比紧耦合的请求响应实现复杂得多,因为它需要更多的基础结构。

    我来解释一下。在使用标准 HTTP 的同步消息处理模型中,客户端在向服务器发送请求后阻塞,直至从服务器接收到响应。在这段时间内,可能会发生许多灾难性事件:

    • 连接可能会因外部原因而断开,从而丢失请求或响应。

    • 服务器可能会因脱机或过载而超时。

    • 服务器进程可能取决于下行服务,而这种服务的响应时间无法控制。

    同步模型


    图 1. 同步模型


    不管问题是与网络有关还是与应用程序有关,要确保可靠性都需要实现某种由附加协议驱动的基础结构。在本次讨论中,我想着重介绍消息是如何在传输层上进行处理的。传输层是独立于应用程序的关键部分,使用它可以实现可靠性层,并将消息的最终处理过程分离出来。更具体地说,每一条消息(不管哪种应用程序)都需要从网络层上读取,并调度至适当的应用程序资源。我们可以在这里添加一个发送可靠性确认和执行持续存储的附加协议,这样应用程序资源就可以选择处理该消息的时间和方式。另外,这个新协议可以帮助分离或加快异步处理模型。下面我将解释如何完成此过程。

    在下面的异步模型中,有一个请求被发送到 SOAP 服务器。服务器从网络层上读取该消息流,并立即向客户端返回 HTTP 202 响应。此进程仅就向服务器发送消息的时间而言是同步的,这样可以减少与连接有关的问题。到达服务器后,消息将被传递经过可靠性层,在此进行检查以验证消息是否过期、重复和有序。接着,消息存储到持续存储区(关系数据库)中,并向客户端发送有关其状态的确认。最后,消息将被调度至预定的应用程序功能。

    异步模型


    图 2. 异步模型


    在 HTTP 环境中,您可以控制何时向客户端发回响应。通过控制向客户端发回响应的时间,您可以将下行处理影响通讯可靠性的风险降到最低。在 SOAP 中,这是通过单向消息实现的。它命令基础 SOAP 处理器立刻向客户端发送 HTTP 202 响应,通知客户端已收到消息,并已成功地将消息调度给正确的资源进行处理。之后,处理器向客户端发送有关该消息状态的响应。本文稍后将对这种模型的优点进行详细介绍。

    返回页首
    构建可靠性层
    记住了上述要求之后,我们来讨论如何使用 .NET 框架为 Web 服务实现构建可靠性协议。根据上述要求,我建立了一个小型 API,以便提供可用的实现。

    协议:ericRP
    我动手处理的第一个问题是定义如何分解可靠性协议 (ericRP)。以下是该协议的要点:

    • 该协议是用于教学的原型。

    • 该协议主要是通过扩展消息处理层 (SOAP) 在 SOAP 处理层上执行。

    • SOAP 头用于对处理层所需的信息进行编码。

    • 该协议要求实现具有某种方式的持续存储以记录消息。本实现使用的是 Microsoft SQL Server 2000。

    注意 不管采取哪种方式为 SOAP 环境实现可靠性层,除了 SOAP 分析器之外,还需要其他基础结构。

    • 该协议支持对话概念,也就是说可以对多条消息进行排序,从而保证有序的传送。

    • 该协议的全部实现都由 ericRP 命名空间限定。

    • ericRP 基于两方对话方案。具体地说,两个服务可以通过 XML Web 服务结构(HTTP、SOAP 和 WSDL)进行对话。

    • 客户端负责消息的所有更正。(本文后面有详细论述)

    • 服务器只负责基于某个标准发送确认。

    • 不记录服务器收到的过期消息。

    • 不记录服务器收到的无序消息。

    • 不记录服务器收到的重复消息。

    处理 API
    对于这个原型,我构建了六个主要的类和一个小型数据库。我将类称为处理 API。Web 服务客户端和服务器将使用这些类监视和更正使用 ericRP 可靠性协议的消息。所有的类都属于 ericRP 命名空间:

    • Client.ConversationManager — 由客户端使用,为 Web 服务消息关联和消息监视创建对话上下文。

    • Client.RPClientTrace — 由 Web 服务客户端使用,这些客户端的方法对出站消息执行 ericRP 可靠性协议。

    • Server.ConversationManager — 由 Web 服务服务器使用,用于记录并处理入站消息。

    • Server.RPServerTrace — 由 Web 服务服务器使用,这些服务器的方法为入站消息实现 ericRP 可靠性协议。

    • ReliabilityInfo — 具有双重作用。由 Client.ConversationManager 使用,为记录提供可靠性信息;也可以由 Web 服务客户端代理使用,为出站消息创建必要的 SOAP 头信息。

    • Acknowledgment — 由 Server.ConversationManager 使用,用于向客户端发送确认。

    返回页首
    ericRP 的工作原理
    在查看代码之前,我想先从用户的角度说明该协议的工作原理。在我的示例中,我有一个简单的 Web 服务代理类,通过它可以向 Web 服务发送订单消息。将要使用 API 的客户端需要执行以下操作。

    首先,创建 Client.ConversationManager 类的实例并开始一个新对话。例如:

    private void begin()
    {
    rpClient = new ericRP.Client.ConversationManager();
    rpClient.MessageSent += new _
       ericRP.Client.ConversationManager.MessageSentEventHandler(process);
    rpClient.ConversationStarted += new _
       ericRP.Client.ConversationManager.ConversationStartedHandler(constarted);
    rpClient.BeginConversation();
    }

    rpClient 变量在类级别内有效,稍后会用到。我还设置了一些事件处理程序。

    下一步,结合使用订单代理和 ReliabilityInfo 类,发送一条可靠的信息。首先,创建 PurchaseOrderProxy 的一个实例,就象通常为 Web 服务客户端所做的一样。接着,创建 ReliabiltiyInfo 类的一个实例,将 ConversationManager 传递给构造函数,然后设置可靠性属性。需要特别注意的属性是 MaxRetry、ExpireDate 和 AckURL。MaxRetry 和 ExpireDate 用于限制消息的活动,防止它无限制地传送。AckURL 由 Web 服务在向客户端发送接收确认时使用。设置完这些属性后,即可设置代理的 ReliableHeader 属性并调用所需的方法。

    private void sendMessage()
    {
    ClientProxies.PurchaseOrderProxy po = new ClientProxies.PurchaseOrderProxy();
       ericRP.ReliabilityInfo rInfo = new ericRP.ReliabilityInfo(rpClient);
       rInfo.Status = ReliabilityInfo.MessageStatus.New;
       rInfo.SendDate = System.DateTime.Now;
       rInfo.ExpireDate = System.DateTime.Now.AddHours(4);
       rInfo.MaxRetry = 5;
       rInfo.AckURL = "http://localhost:8082/ericRPAck/POAck.asmx";
       po.ReliableHeader = rInfo;
       po.SubmitMessage("sure hope they get this purchase order!");
    }

    这是为了说明该功能而编写的一段客户端测试程序的屏幕快照。请注意,我们一共发送了五条消息。第三条消息在到达目的地之前已过期,按照 ericRP 协议,这条消息将被丢弃,服务器不对其进行处理。第四条消息被认为是无序消息,因为服务器从未收到有效的第三条消息。在重新发送第三条消息之前,任何后续消息都是无序的。如果重新查询 Client.ConversationManager,您将发现第五条消息也是无序的。

    图 3. 客户端测试程序


    返回页首
    头的作用
    在查看代码之前,我们需要了解一下 SOAP 主题,即头。SOAP 1.1 规范中谈论最少的内容之一就是 SOAP 头。头提供了一种扩展消息处理结构的简单方法。SOAP 1.1 规范中提到:头在实现与消息主体没有明确关系的处理规则(如身份验证和事务管理)时非常有用。对任何类型的消息来说,SOAP 头都是以独立方式对可靠性信息进行编码的完美解决方案。规范中还概述了实施和处理这些头时应该采用哪些标准和规则。

    让我们来看一看如何实现包含可靠性信息的 SOAP 头。首先要为头确定架构。这很重要,因为它正是最终用户在支持该头的 Web 服务的 WSDL 文件中看到的实际内容。对于此实现,我有效地将处理 API 直接映射到 SOAP 头。

    我来解释一下。在我的处理 API 中,有一个名为 ReliabilityInfo 的类。此类实例化后将在运行时变成动态对象。也就是说,您可以设置属性,确定从可靠性的角度将如何处理出站消息。此对象还可以在运行时序列化为 SOAP 头。下面是该类及其成员的一个快照。为清楚起见,我删除了实现和私有成员。

    [XmlRootAttribute(ElementName="ReliableHeader", _
       Namespace="http://ericRP/ReliableHeader/2001/", IsNullable=false)]
       public class ReliabilityInfo : SoapHeader
       {      
          public string Destination{}
          public string ConversationId{}
          public int MessageId{}
          public MessageStatus Status{}
          public DateTime SendDate{}
          public DateTime ExpireDate{}
          public string AckURL{}
    public enum MessageStatus{}
    [XmlIgnore]
          public int MaxRetry{}
          [XmlIgnore]
          public string Text{}
       }

    当头序列化为出站 SOAP 消息时,它如下所示:

    <soap:Header>
    <ReliableHeader xmlns="http://ericRP/ReliableHeader/2001/">
    <ConversationId>b9e029e1-af0f-42cb-83b0-7888f9e3ffc4</ConversationId>
    <MessageId>1</MessageId>
    <Status>New</Status>
    <SendDate>2001-11-06T14:59:02.1021226-08:00</SendDate>
    <ExpireDate>2001-11-06T18:59:02.1021226-08:00</ExpireDate>
    <AckURL>http://localhost:8082/ericRPAck/POAck.asmx</AckURL>
    </ReliableHeader>
    </soap:Header>

    这是通过 .NET 框架中两个非常重要的类实现的。基本 XML 序列化块使用 System.Xml.Serialization 命名空间类来进行处理。我使用 XmlRootAttribute 属性类,告诉序列化程序我希望将文档片断的根称为 ReliableHeader 并将它与命名空间相关联。此后,除非您告诉序列化程序忽略该成员,否则所有公共成员也同样会被序列化。我使用的另一个重要命名空间是 System.Web.Services.Protocols。具体地说,我使用 SoapHeader 类。从该类进行继承时,它会自动将序列化的 XML 加入到 SOAP 消息中。本文稍后将论述如何将头挂钩到消息中。

    这非常强大,因为我不仅可以使用强类型化的已编译对象作为头的基础,而且这些类在其成员内部还可能有非常具体的实现。

    返回页首
    把代码合在一起
    好了,我已对可靠性进行了简单的论述,并阐述了我自己的规范。现在,我们将查看使它运行的代码。

    扩展 Web 服务客户端代理
    第一步是重新设置现有的 .NET Web 服务客户端代理。切记,此协议可以在任何 SOAP 处理引擎中实现。我选择了 .NET 框架,因为它易于使用、基于标准且可扩展。

    选取一个现有的 Web 服务客户端代理(例如 PurchaseOrderProxy),然后添加以下代码:

    • 该类中必须有名为 ReliableHeader 的公共成员,并且其类型必须为 ericRP.ReliabilityInfo。此成员将在运行时通过调用客户端进行设置。稍后将使用此成员为出站消息提供头信息,并提供在跟踪过程中应用了该头的消息的状态信息。例如:public class PurchaseOrderProxy : System.Web.Services.Protocols.SoapHttpClientProtocol { public ReliabilityInfo ReliableHeader; //Additional code omitted for clarity }

    • 在 Web 服务客户端代理中调用的方法必须使用以下属性进行注释: [SoapHeader("ReliableHeader", Required=true)]在序列化过程中,此属性将在运行时把适当的头值加入到出站 SOAP 消息中。此处的 SubmitMessage 方法使用 SoapHeader 属性进行标记。请注意,ReliableHeader 是在步骤 1 中实现的成员,而且这是必须的。也就是说,如果不在运行时设置此成员,将引发异常。例如: [SoapHeader("ReliableHeader", Required=true)]public void SubmitMessage(object message) {this.Invoke("SubmitMessage", new object[] {message}); }

    • 在 Web 服务客户端代理中调用的方法必须包括以下属性: [ericRP.Client.RPClientTrace.TraceExtension()]此属性表示该方法支持自定义 SOAP 扩展。在消息被序列化之前和之后、且在消息被发送至基础传输机制之前,此 SOAP 扩展将在运行时被调用。我通常是在消息从客户端计算机发送出去之前,对它进行一些简单的跟踪和记录。稍后再查看此扩展的实现情况。例如: [ericRP.Client.RPClientTrace.TraceExtension()][SoapHeaderAttribute("ReliableHeader", Required=true)]public void SubmitMessage(object message) {this.Invoke("SubmitMessage", new object[] {message}); }

    • 该类必须从 ericRP.Client.RPClientTrace.IClientTrace 实现。这种接口实现提供了基础跟踪功能,以检查调用方是否支持特定的跟踪协议。在后面的跟踪功能中可以看到此代码。例如: public class PurchaseOrderProxy : System.Web.Services.Protocols.SoapHttpClientProtocol, ericRP.Client.RPClientTrace.IClientTrace{public ReliabilityInfo ReliableHeader; }

    • 最后,该类必须实现IClientTrace.GetReliabilityInfo 函数,该函数是 IClientTrace 接口所需的唯一函数。这是一个简单的机制,客户端可以使用它在运行时将消息的状态信息传递到跟踪服务。例如: public class PurchaseOrderProxy : System.Web.Services.Protocols.SoapHttpClientProtocol, ericRP.Client.RPClientTrace.IClientTrace{public ReliabilityInfo ReliableHeader;ericRP.ReliabilityInfo _ ericRP.Client.RPClientTrace.IClientTrace.GetReliabilityInfo(){ return ReliableHeader;} }

    看起来代码可能很多,但实际上却很简单。事实上,如果时间再多一些,我本可以创建从 SoapHttpClientProtocol 继承的新类并显式地实现它,但这种方式对于服务器端来说会更有趣。

    扩展 Web 服务服务器 stub
    接着,我们打算扩展现有的 Web 服务服务器 stub。采用一个现有的 .NET Web 服务类 (ProcessPurchaseOrder),然后添加以下代码:

    • 该类中必须有一个类型为 ericRP.ReliabilityInfo 的公共成员 ReliableHeader。稍后将使用此成员为入站消息提供反序列化头信息,并提供在跟踪过程中应用了该头的消息的状态信息。例如: public class ProcessPurchaseOrder : System.Web.Services.WebService { public ReliabilityInfo ReliableHeader; }

    • 在 Web 服务 stub 中调用的方法必须使用以下属性进行注释: [SoapHeader("ReliableHeader", Required=true)]在反序列化过程中,此属性将在运行时对入站 SOAP 消息中适当的头值进行反序列化。此处的 SubmitMessage 方法使用 SoapHeader 属性进行标记。例如: [WebMethod][SoapHeader("ReliableHeader", Required=true)]public void SubmitMessage(object message) {//Code omitted for clarity }

    • 在 Web 服务 stub 中调用的方法必须使用以下属性进行注释: [ericRP.Server.RPServerTrace.TraceExtension()]此属性表示该方法支持自定义 SOAP 扩展。稍后查看此扩展的实现情况。 注意 此扩展与客户端扩展不同。 例如: [SoapHeader("ReliableHeader", Required=true)][ericRP.Server.RPServerTrace.TraceExtension()]public void SubmitMessage(object message) {//Code omitted for clarity}

    • 在 Web 服务 stub 中调用的方法必须使用以下属性进行注释: [SoapDocumentMethod(OneWay=true)]此属性表示被调用的函数不返回值。更具体地说,一旦消息被反序列化,此属性就会强制 Web 服务向客户端返回 HTTP 202 响应。对于分离消息的最终处理来说,这是一个有效的机制,否则,客户端就必须同步地等待服务返回响应。例如: [WebMethod][SoapDocumentMethod(OneWay=true)][SoapHeader("ReliableHeader", Required=true)][ericRP.Server.RPServerTrace.TraceExtension()]public void SubmitMessage(object message) {//Code omitted for clarity }

    • 该类必须从 ericRP.Server.RPServerTrace.IServerTrace 实现。这一接口实现提供了基础跟踪功能,以检查调用程序是否支持特定的跟踪协议。在后面的跟踪功能中可以看到此代码。例如: public class ProcessPurchaseOrder : System.Web.Services.WebService, ericRP.Server.RPServerTrace.IServerTrace { public ReliabilityInfo ReliableHeader; }

    • 最后,该类必须实现 IServerTrace.GetReliabilityInfo 函数。这是 IServerTrace 接口所需的唯一函数。例如: public class ProcessPurchaseOrder : System.Web.Services.WebService, ericRP.Server.RPServerTrace.IServerTrace { public ReliabilityInfo ReliableHeader;ericRP.ReliabilityInfo _ ericRP.Server.RPServerTrace.IServerTrace.GetReliabilityInfo() { return ReliableHeader; } }

    好了,我们已改进了现有的 Web 服务客户端和服务器。下面我们来看看 SoapExtension 是如何工作的。

    查看 RPClientTrance 和 RPServerTrace

    为了实现可靠性处理,我决定使用 SoapExtension。SoapExtension 是一个可继承的基类,使用它可以跟踪 SOAP 消息的出站序列化和入站反序列化。正是在这个跟踪过程中,对消息进行记录并检查其状态。记得前面的步骤中讲过,Web 服务客户端代理方法实现 [ericRP.Client.RPClientTrace.TraceExtension()]。在该方法被调用时,此属性将在 SOAP 消息出站序列化时调用以下代码。

    需要特别指出的主要函数是 ProcessMessage。如果您要发送出站消息,ProcessMessage 将提供有关该消息序列化之前和之后的全部状态信息。这时,我检查谁在调用并将 Client 属性的类级别成员与当前的消息分离。然后检查消息是否处于 AfterSerialize 状态。一旦完成序列化,我就可以在消息被发送至服务器之前进行记录。使用名为 ProcessOutgoingMessageText 的自定义函数,我首先进行一些流交换以免破坏基础消息流。接着,检查客户端是否支持 IClientTrace 接口。如果客户端支持该接口,则表明它们也支持可靠性协议。通过接口检查功能,可以调用 GetReliabilityInfo,以便将当前消息返回可应用于该消息的 ConversationManager,然后设置一些属性并调用 LogMessage。LogMessage 将当前消息信息写入本地数据库,然后引发事件,通知客户端该消息已被记录。

    public class RPClientTrace : SoapExtension
    {      
    public override void ProcessMessage(SoapMessage message)
    {
      SoapClientMessage tmpMsg = (SoapClientMessage)message;
      _client = tmpMsg.Client;
      if (message.Stage == SoapMessageStage.AfterSerialize)
      {
        ProcessOutgoingMessageText(message);
      }
    }
      public void ProcessOutgoingMessageText(SoapMessage message)
      {
       newStream.Position = 0;
       TextReader reader = new StreamReader(newStream);
       StringBuilder strMessage = new StringBuilder();
       strMessage.Append(reader.ReadToEnd());
       newStream.Position = 0;
       Copy(newStream, oldStream);
       if(_client is Client.RPClientTrace.IClientTrace)
       {
        try
        {
    Client.RPClientTrace.IClientTrace _ptrClient = _
       (Client.RPClientTrace.IClientTrace)_client;
       ReliabilityInfo rInfo = _ptrClient.GetReliabilityInfo();
          rInfo.Text = strMessage.ToString();
          rInfo.Destination = message.Url;
       rInfo.Manager.LogMessage(rInfo);
         }
         catch(Exception e)
         {
          throw e;
         }
        }
       }
    }

    服务器端的情况有点复杂,因为服务器需要为入站消息执行额外的操作。被调用的 Web 方法用于实现 [ericRP.Server.RPServerTrace.TraceExtension()]。下面的代码将在入站消息反序列化之前和之后被调用:

    public class RPServerTrace : SoapExtension
    {
    public override void ProcessMessage(SoapMessage message)
    {
    try
    {
      switch (message.Stage)
      {
       case SoapMessageStage.BeforeDeserialize:
            ReadIncomingMessageText(message);
        break;
       case SoapMessageStage.AfterDeserialize:
         SoapServerMessage tmpMsg = (SoapServerMessage)message;
         _server = tmpMsg.Server;
         if(_server is Server.RPServerTrace.IServerTrace)
         {
              Server.RPServerTrace.IServerTrace _ptrServer = _
       (Server.RPServerTrace.IServerTrace)_server;
         ReliabilityInfo rInfo = _ptrServer.GetReliabilityInfo();
       ericRP.ReliabilityInfo tempInfo = (ericRP.ReliabilityInfo)message.Headers[0];
       tempInfo.Text = _tempMessage;
       Server.ConversationManager manager = new Server.ConversationManager();
       manager.ProcessMessage(tempInfo);
         }
       break;
       }
    }

    在进行流交换和接口检查后,将在服务器对话管理器上调用 ProcessInboundMessage。ProcessInboundMessage 用于检查核心消息的状态。消息缓冲器即在此使用。首先检查消息是否过期,然后检查其是否重复,最后检查其是否有序。如果满足所有这三个条件,则将记录该消息并向客户端发回确认。如果不能满足任一条件,则将更改消息的状态并向客户端发回确认。

    public void ProcessInboundMessage(ericRP.ReliabilityInfo rInfo)
    {         
        try
        {
       if(IsExpired(rInfo))
       {
       rInfo.Status = ericRP.ReliabilityInfo.MessageStatus.Expired;
       SendAck(rInfo);
       }
       else if(IsDulplicate(rInfo))
       {
       rInfo.Status = ericRP.ReliabilityInfo.MessageStatus.Duplicate;
       SendAck(rInfo);
       }
       else if(IsNotOrdered(rInfo))
       {
       rInfo.Status = ericRP.ReliabilityInfo.MessageStatus.NotOrdered;
       SendAck(rInfo);
       }
       else
    {
       rInfo.Status = ericRP.ReliabilityInfo.MessageStatus.Success;
       LogMessage(rInfo);
       SendAck(rInfo);
       }
        }
        catch(Exception e)
        {
       throw e;
        }
      }
    }

    要使本示例在生产环境中可行,还需要做大量的实现工作。更重要的是,API 应当基于一个以后将会发布的公共标准。本文的主要目的就是引发读者思考问题,了解一下 .NET 框架中的核心 Web 服务类,我想这两个目的都已经达到。如果您正在为可靠的异步消息处理寻求成熟的现成实现,建议您看一看 Microsoft BizTalk? Server 2000。

    最后,您可以使用类似的跟踪功能执行所有类型的操作,如加密、自定义调度和通知。切记,这项附加功能增加了 Web 服务所需的处理基础结构的数量。

    返回页首
    展望
    无论是在规范还是在实现方面,XML Web 服务的未来都是光明的。Microsoft 将以协作的、标准驱动的方式工作,确保 XML Web 服务成为编写松散耦合的分散式应用程序的最佳结构。可靠的消息处理和事务规范将在以后发布。尽管还有大量的实现工作要做,但您现在就可以开始使用 SOAP 和 WSDL 构建框架。与公共规范进程越接近,以后的移植工作就越容易进行。SOAP 规范就是这种概念的一个显著例子。世界各地的开发人员都可以跟踪 SOAP 规范的发展进程,因此可以轻松地对自己的实现进行相应的调整。

    希望我有一个魔术球,为您准确地描绘未来 XML Web 服务的基础结构。希望我们目前依赖的所有公用服务(安全性、事务、存储、队列、远程处理和进程协调等),将来都能够直接映射到 Web 服务结构。另外,GXA 实现可以渗透到核心开发语言、应用程序框架、业务处理框架和企业基础结构中。到那时,我们就能够真正地以无缝方式将任意两种服务耦合在一起。但愿 ericRP 不会真的成为服务背后的可靠性层。<微笑>


       收藏   分享  
    顶(0)
      




    ----------------------------------------------
    我只知道,用 xml 做网站,可以省我很多时间.

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2004/7/21 13:34:00
     
     GoogleAdSense双鱼座1979-3-8
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 最新动态 & 业界新闻 』的所有贴子 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2024/5/17 6:25:46

    本主题贴数1,分页: [1]

    管理选项修改tag | 锁定 | 解锁 | 提升 | 删除 | 移动 | 固顶 | 总固顶 | 奖励 | 惩罚 | 发布公告
    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    70.313ms