Fork me on GitHub

WCF 4.0路由服务Routing Service

在面向服务的应用系统中,最重要的概念就是消息,消息的传输是一个非常重要的问题。而在大多数情况下,消息要经历多个网络节点,这里会涉及到消息路由问题。WS规范很早就制定了对于消息路由问题的解决办法,这里最早的就是WS-Routing 。当然后来逐渐为更完善的规范WS-Addressing取代。

支持对于消息路由,WCF4.0之前的框架没有提供支持,在WCF4.0里又重新加入对于消息路由机制的支持。当然这里我们学习消息路由,首先还是来了解一下与消息路由相关的一些规范,下面我们就来依次看一下WS-Routing和WS-Addressing。

WS-Routing(WS-路由):

早期的SOAP消息因为存在路径依赖问题,因此不能实现在多个协议之间转发,而WS-Routing 是解决路径依赖问题的第一个规范。WS-Routing 使您能够以传输中立的方式指定消息路由和调度信息。

Web服务路由规范(WS-Routing)定义了路由SOAP消息的机制。SOAP是一个轻量级的有线传输协议,定义了一系列传输交换机制,用来传输在应用层协议上使用的方法调用。SOAP实际上没有定义从一点发送消息到另一点的机制,即使在它的规范中它引用了一个虚拟的消息路径机制。WS-Routing(以前被称作SOAP路由协议)是一个无状态协议,他扩展了SOAP协议,WS-Routing通过定义一个方法来说明一个预先设计好的路由或传输路径,这个路径将从消息源,经过若干中介,最后到达消息的最终接受者。

WS-Routing 定义了要在 SOAP 标头块中使用的新元素(名为 <r:path>)。这个路径元素有几个子元素,它们可以用来指定路由和调度信息,包括 <r:to><r:action>。这些元素可以用来相关的路由信息,但不依赖传输协议。当然为了支持更复杂的路由情况,WS-Routing也定义了一些其它可选元素。例子如下:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2001/06/soap-envelope">
<SOAP-ENV:Header>
<wsrp:path xmlns:wsrp="http://schemas.xmlsoap.org/rp/">
<wsrp:action>http://www.xml.org/chat</wsrp:action>
<wsrp:to>soap://dotnetting.cn/some/endpoint</wsrp:to>
<wsrp:fwd>
<wsrp:via>soap://msdn.com</wsrp:via>
</wsrp:fwd>
<wsrp:from>soap://openbeta.cn/some/endpoint</wsrp:from>
<wsrp:id>uuid:00000000-3322-11111-1111-111111111111</wsrp:id>
</wsrp:path>
</SOAP-ENV:Header>
<SOAP-ENV:Body>

</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

这里path节点下面的几个重要子节点的作用如下:

  • "from"元素表示消息来源。或者是发送者地址。
  • "to"元素表示消息最终接受者的地址。
  • "fwd"元素记录发送时经过的路径信息。
  • "rev"元素回发消息的反向路径信息,这个可以在发送消息的过程中生成。

WS-Routing通过定义"rev"元素从而允许双向的消息交换。"fwd"和"rev"元素都包含"via"元素,"via"元素用于描述每一个消息途径的节点,也就是中间的消息参与者。而"fwd"和"rev"元素包含的其他元素则被用于定义消息的标识、相关性和目的。

尽管这种消息内路由功能非常强大,,但它也存在一些安全问题。路由器必须修改标头。如果我们需要对消息头进行签名,则原始的发送方无法在签名消息(包括 WS-Routing 标头)之后并在不破坏原始签名的情况下使用 WS-Routing 路径发送消息。如果不对消息头加密,则存在很大的安全隐患。

为了解决这些安全性就出现了一种更简单的基于 SOAP 路由的方法:WS-Addressing。

WS-Addressing(WS-寻址):

为了改进WS-Routing ,WS-Addressing 为 Web 服务寻址提供了传输中立的机制。WS-Addressing 使上述 WS-Routing 的简化形式化,并且添加了少量其他功能。

1)基本概念:

WS-Addressing 放弃了与消息路径相关的 WS-Routing 元素(包括 <r:path>、<r:fwd> 和 <r:rev>),并且假定用户将依靠“下一个跃点”方式来解决路由需要。 <wsa:To> 指定消息的目标,<wsa:Action> 指定操作, <wsa:MessageID> 指定消息ID。如果是应答消息,则使用 <wsa:RelatesTo> 标头和它的 RelationshipType 属性来表示该应答消息与请求消息之间的关系。

2)终结点引用:

此外,WS-Addressing 还引用终结点引入了新终结点引用机制。这使得可以在消息中传递终结点引用(叫做“按引用传递”),这样就可以告诉接收方应答消息的发送地址。

我们看一个完整的WS-Addressing 的例子:

<s:Envelope>
<s:Header>
<wsa:Action>http://shanyou.cnblogs.com/SubmitForm</wsa:Action>
<wsa:To>http://shanyou.cnblogs.com/Claims/Submit.asmx</wsa:To>
<wsa:From>
<wsa:Address>http://shanyou.cnblogs.com/main/sub.asmx</wsa:Address>
<wsa:ReferenceProperties>
<c:PatientProfile>333333333</c:PatientProfile>
<c:CarrierID>444444</c:CarrierID>
</wsa:ReferenceProperties>
</wsa:From>
<wsa:ReplyTo>
<wsa:Address>http://shanyou.cnblogs.com/response/response.asmx</wsa:Address>
<wsa:ReferenceProperties>
<c:PatientProfile>333333333</c:PatientProfile>
<c:CarrierID>4444444</c:CarrierID>
</wsa:ReferenceProperties>
</wsa:ReplyTo>
<wsa:FaultTo>
<wsa:Address>http://shanyou.cnblogs.com/fault/error.asmx</wsa:Address>
<wsa:ReferenceProperties>
<c:PatientProfile>11111111</c:PatientProfile>
<c:CarrierID>2222222</c:CarrierID>
</wsa:ReferenceProperties>
</wsa:FaultTo>
</s:Header>
<s:Body xmlns:c="http://xml.org/claims">
<c:SubmitClaim> … </c:SubmitClaim>
</s:Body>
</s:Envelope>

我们可以看到SOAP消息头关于<wsa:From><wsa:ReplyTo><wsa:FaultTo>的定义。

WCF相关类型:

另外因为SOAP和WS-Addressing 规范都存在不同的版本, SOAP的两个版本分别是SOAP 1.1和SOAP 1.2。而WS-Addressing 当前有两种版本:WS-Addressing August 2004 和 WS-Addressing 1.0。WCF为了提供完善的支持,在MessageVersion类里都给出了定义。这些版本可以分别通过使用 WSAddressingAugust2004WSAddressing10 属性进行检索。两者的对应关系,在WCF的类库里可以通过MessageVersion控制。MessageVersion的类型定义如下:

public sealed class MessageVersion
{
public static MessageVersion Default { get; }
public static MessageVersion None { get; }
public static MessageVersion Soap11 { get; }
public static MessageVersion Soap11WSAddressing10 { get; }
public static MessageVersion Soap11WSAddressingAugust2004 { get; }
public static MessageVersion Soap12 { get; }
public static MessageVersion Soap12WSAddressing10 { get; }
public static MessageVersion Soap12WSAddressingAugust2004 { get; }
}

这个就是我们看到的WCF内部对于SOAP消息寻址规范支持的类型,WCF框架会使用这个类型来控制消息使用的SOAP消息以及WS-Addressing 的版本。

我们现在来了解一下WCF如何调用一个特定的服务方法的。这也是WCF路由服务涉及到的重要内容。

我们知道,在客户端,我们可以通过代理类来调用一个服务的方法。这其实在背后,WCF框架为我们生成了一个SOAP消息。而这个SOAP消息包含我们要调用服务的必要信息。我们看一下简单的SOAP消息的例子:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://tempuri.org/IService1/GetData</Action>
</s:Header>
<s:Body>
<GetData xmlns="http://tempuri.org/">
<value>1</value>
</GetData>
</s:Body>
</s:Envelope>

这个是默认创建的WCF服务程序的客户端调用的SOAP消息结构。但是这个消息又是如何在服务端调用到特定的方法的呢?

在WCF中,每个服务端点实际上有两个地址:

  1. 逻辑地址:逻辑地址(“To”)是 SOAP 消息的目标地址。

  2. 物理地址:物理地址(“Via”)是 WCF侦听消息的实际传输特定网络地址。

WCF通道基础结构针对的是物理地址,因为物理地址负责使用特定的传输协议在特定的位置ListenURI接收传入的消息。 WCF调度程序避开了这种联网细节,而是关注将传入消息映射到一个端点,并最终到达方法调用。

那么WCF根据什么来实现消息的匹配的呢?这里就要介绍一个重要的概念:消息过滤器。MessageFilter实例负责消息的调度。前面的SOAP中的Action值,是一个消息调度的方式。

当传入消息时,WCF使用消息过滤器器确定匹配端点。我们也可以自己定义消息过滤器器类型。WCF对于自定义消息过滤器器的支持,带来了很大的灵活性。我们可以摆脱传统调度模型,实现SOAP 以外的调度方式 :实现 REST/POX 样式的服务。

每个终结点实际上关联着两个过滤器:

  1. 地址过滤器:确定传入消息是否匹配端点的“To”地址和任何必需的地址标头,
  2. 契约过滤器:确定它是否匹配端点的契约。

两个筛选器都被调度程序用来确定目标端点。

WCF类型系统定义了6个消息过滤器类型以满足不同的需求,它们是:

  • XPathMessageFilter 使用 XPath 1.0 表达式来指定匹配的条件,它是实现基于内容路由的核心消息过滤器。
  • MatchAllMessageFilter 与所有消息相匹配。
  • MatchNoneMessageFilter 与所有消息都不匹配。
  • ActionMessageFilter 测试消息操作是否为指定的操作集之一。也就操作匹配。
  • EndpointAddressMessageFilter 测试消息是否满足指定的终结点地址。
  • PrefixEndpointAddressMessageFilter 对消息 URI 的前缀进行匹配,只要传入的“To”地址与端点地址有相同的地址前缀(一种松散匹配),将导致两者匹配。

WCF过滤器只是 MessageFilter的子类。MessageFilter 有几个内置实现,包括 EndpointAddressMessageFilter 和 ActionMessageFilter,它们分别作为默认地址和契约过滤器。

EndpointAddressMessageFilter 仅仅将“To”地址与端点地址进行比较,预期它们完全匹配。它也将传入消息中获得的寻址标头和终结点要求的一组寻址标头进行比较。

ActionMessageFilter 将传入的“Action”值和约定上的操作进行比较,再次预期完全匹配。

PrefixEndpointAddressMessageFilter 只要传入的“To”地址与端点地址有相同的地址前缀(一种松散匹配),将导致两者匹配。

MatchAllMessageFilter,它导致所有消息匹配给定端点。

我们可以通过 [ServiceBehavior] 的 AddressFilterMode 属性来选择消息过滤器。使用 PrefixEndpointAddressMessageFilter的例子代码:

[ServiceBehavior(AddressFilterMode=AddressFilterMode.Prefix)]
public class CalculatorService : ISimpleMath, IScientif

WCF4.0实现了一个路由服务类型RoutingService,它可以支持多种消息交换模式的消息路由场景:单向、请求/应答、双工。RoutingService的定义如下:

namespace System.ServiceModel.Routing
{
// Summary:
// Defines the routing service, which is responsible for routing messages between
// endpoints based on filter criteria.
[ServiceBehavior(AddressFilterMode = AddressFilterMode.Any, InstanceContextMode = InstanceContextMode.PerSession, UseSynchronizationContext = false, ValidateMustUnderstand = false)]
public sealed class RoutingService : ISimplexDatagramRouter, ISimplexSessionRouter, IRequestReplyRouter, IDuplexSessionRouter
{
}
}

我们注意到RoutingService 类型为了支持不同的消息交换模式,实现了多个契约接口: ISimplexDatagramRouter、
IRequestReplyRouter、IDisposable。为了实现回会话路由,它也实现了ISimplexSessionRouter、IDuplexSessionRouter接口。路由服务会根据消息过滤器的条件在服务终结点之间来转发消息。也就是路由消息。

WCF4.0新特性体验(6):路由服务Routing Service(下)

Getting Started with WCF 4.0 Routing Service

WCF Router LoadBalancer

posted @ 2011-07-22 22:13  张善友  阅读(4381)  评论(0编辑  收藏  举报