使用路由服务类
实现手动路由无疑是非常强大的技术,但是常见的场景下你所希望的仅仅是,基于请求的某些特性而不是编写一些动态的算法以实现路由消息。为了处理这样的场景,WCF提供了RoutingService类,该类位于System.ServiceModel.Route命名空间下。给命名空间下的类图如下图所示:
RoutingService类的目的在于:当消息达到时,基于内容实现路由。你可以配置RoutingService对象,使其检查消息头部的信息然后路由消息;甚至还可以使其转化消息体的内容然后基于转化后的内容路由请求。你可以通过包含一个或多个路由过滤器(过滤器指定了与消息的匹配条件以及和当匹配成功后消息推送目的地信息)的过滤表配置RoutingService类。一个路由过滤器实际上是MessageFilter类的实例。
你可以动态地创建MessageFilter对象,并将其与RoutingService对象关联。但大多数完成方式是静态地为每个路由过滤器添加过滤信息到寄宿RoutingService对象的应用程序的配置文件中;并使WCF运行时在运行服务时根据配置文件创建必要的MessageFilter对象。在下面练习中我们也将使用该方式。
在下面的练习中,你将更改ShoppingCartService服务的路由策略。不再使用负载均衡算法交替地发送请求至在不同端口侦听请求的ShoppingCartService实例;你将基于请求的类型路由消息:AddItemToCart消息和RemoveItemFromCart消息将被路由到ShoppingCartService服务的一个实例,而GetShoppingCart和CheckOut消息将路由到另外一个实例。
练习:寄宿和配置RoutingService服务
1. 使用Visual Studio打开WCF\Step.by.Step\Solutions\Chapter14\ShoppingCartServiceWithRouter文件夹下的ShoppingCart.sln解决方案。
该方案包含持续性ShoppingCartService服务,ShoppingCartServiceHost和ShoppingCartGUIClient项目,它从第七章复制过来。当前,ShoppingCartService服务配置了两个HTTP端点,这两个端点在9010和9020侦听请求,它们使用BasicHttpContextBinding绑定。
2. 添加一个新的控制台应用程序项目到ShoppingCart解决方案中。该控制台项目的名字为StaicRouter,并保存在WCF\Step.by.Step\Solutions\Chapter14\ShoppingCartServiceWithRouter文件夹下。
3. 引用System.ServiceModel, System.ServiceModel.Routing组件到StaticRouter项目,然后再引用项目ShopingCartService到StaticRouter项目。
4. 打开StaticRouter项目的Programm.cs文件;然后在文件的头部添加下面的using语句
5. 添加下面的代码(高亮部分)到programcs文件main方法中:
上述的代码你现在应该非常熟悉。该代码创建RoutingService类的一个实例,然后将其寄宿在ServiceHost对象中。你将在后续的步骤中为该服务定义配置文件。你还将制定ShoppingCartService服务的地址以使客户端的请求能路由到该地址。
6. 为StaticRouter项目添加配置文件,然后使用WCF服务配置管理器打开该配置文件。
7. 在配置面板,在服务文件夹上点击右键,然后点击创建新的服务。在右边的面板中,在名字字段处输入System.ServiceModel.Routing.RoutingService。该名字为RoutingService类的完整名。
8. 在配置面板,选择新创建服务,然后在其文件夹下的端点处点击右键,然后选择创建新的服务端点。在服务端点面板,按照下表的内容设置对应的属性的值。
属性
|
值
|
地址
|
http://localhost:9000/ShoppingCartService/ShoppingCartService.svc
|
绑定
|
basicHttpContextBinding
|
合约
|
System.ServiveModel.Routing.IRequestReplyRouter
|
合约定义了RoutingService对象实现的消息传输模式。IRequestReply接口基于一个通道处理基本的请求/回复双向模式,推送客户端的请求消息至服务并路由服务的响应消息到对应的客户端。还可以使用其他的合约。比如IDuplexSessionRouter,该接口允许RoutingService对象路由服务器的回调消息到客户端;或者ISimplexSessionRouter,该接口单向地路由消息到实现Session的服务;或者ISimplexDatagramRouter,该接口支持没有提供Session的服务。
注意:在第16章,我们将详细介绍如何创建并使用双向通道。
IRequestReplyRouter接口定义在System.ServiceModel.Routing命名空间下,其内容如下所示:
IRequestReplyRouter接口允许RoutingService类异步地推送请求和响应消息;该接口还支持事务。请注意Action和ReplyAction属性均被标注为*.
9. 在配置面板,展开高级文件夹,然后点击服务行为文件夹。在服务行为面板中,点击创建新的服务行为配置链接。
10. 在右边面板中,清除行为的名字,然后点击添加按钮,然后选择添加一个路由行为元素。该元素包含了你可以用来配置RoutingService服务的行为或者用以指定路由表名字的属性。
11. 在配置面板,展开未命名行为,然后点击路由元素。在右边的面板中,在FilterTableName字段处输入ShoppingCartServiceRoutingTable,请确认RouteOnHeadersOnly属性的值为True,并设置SoapProcessingEnabled属性为False。
你将在后续的步骤中为ShoppingCartServiceRoutingTable过滤表指定消息过滤元素。RouterOnHeadersOnly属性表明:过滤表中过滤元素在路由经过RoutingService服务的消息时,是仅仅定义过滤消息头的规则,还是过滤消息内容的规则。在本练习中,将根据消息头包含的请求动作信息过滤消息,因此RouterOnHeadersOnly属性设置为True。
当RoutingService服务接收到一条请求消息,路由服务基于不同的绑定路由该请求到一个目标服务,这可能与消息传输需求的实现有所不同。SoapProcessingEnabled属性指定了RoutingService服务是否在按照绑定的要求转换消息。如果该属性设置为false,那么路由服务不对消息做任何更改就直接推送消息至目标服务;否则,RoutingService服务将检查消息并将消息的格式转换为目标服务需求的格式。在本练习中,ShoppingCartService服务使用BasicHttpContextBinding绑定在服务和客户端程序之间传输包含了服务实例ID上下文信息。由于你需要将这些上下文信息没有任何干扰的经过RoutingService,因为该属性设置为false。
12. 在配置面板,展开客户端文件夹,然后再端点文件夹上点击右键,然后在添加创建新的客户端端点。在客户端端点面板,按照下表的内容设置对应的属性的值:
属性
|
值
|
名字
|
ShoppingCartServieHttpEndpoint1
|
地址
|
http://localhost:9010/ShoppingCartService/ShoppingCartService.svc
|
绑定
|
basicHttpBinding
|
合约
|
*
|
地址与ShoppingCartHost程序寄宿的ShoppingCartService服务的第一个端点地址相匹配。合约中*号字符表明服务接收任何消息而不是某些指定的服务合约的消息。
请注意Binding属性设置为basicHttpBinding而不是basicHttpContextBinding。客户端程序使用BasicHttpContextBinding绑定连接到RoutingService服务,其使得在消息头部中包含了诸如服务实例的ID这样的上下文信息。如果路由服务也使用上下文绑定连接到ShoppingCartService服务,那么RoutingService服务将会处理从ShoppingCartService服务接收到消息中的上下文信息,把这些上下文信息从消息头部中删除,因此这些上下文信息不会传递给客户端程序。而制定BasicHttpBindg绑定后则会阻止RoutingService服务再 把从ShoppingCartService服务响应的消息回传给客户端之前,从响应消息中查询上下文信息并删除这些上下文信息。此外,在前面步骤中我们已经提到,设置SoapPrecessingEnabled属性为false也阻止了RoutingService服务移除客户端程序发送消息中的上下文信息,因此RoutingService服务直接推送这些消息只ShoppingCartService--不做任何更改。
13. 按照下表内容添加第二个客户端端点
属性
|
值
|
名字
|
ShoppingCartServieHttpEndpoint1
|
地址
|
http://localhost:9020/ShoppingCartService/ShoppingCartService.svc
|
绑定
|
basicHttpBinding
|
合约
|
*
|
14. 保存配置文件,然后退出WCF服务配置管理器
15. 打开StaticRouter项目下的App.config文件,你将会看到上述的端点已经添加到配置文件中。
<fliters>元素中的过滤器列表定义了路由消息的规则。每个过滤器都有一个唯一的名字并且指定了一个filterType,过滤类型指定消息过滤器对象创建的过滤消息的类型。Action类型会导致WCF运行时创建一个ActionMessengerFilter对象,该对象可以基于消息头中的Action元素过滤请求。filterData属性指定了与Action对应的值。如果一个Action与filterData的值匹配,WCF运行时检查<filterTable>片段内的与filter名字像对应的每个实体;然后把消息路由到匹配实体指定的端点。比如,如果RoutingService服务接收到一个消息,该消息的头部的action值为http://
adventure-works.com/2010/06/04/ShoppingCartService/AddItemToCart,那么WCF运行时将路由消息至过滤表中ShoppingCart1实体定义的端点ShoppingCartServiceHttpEndpoint1。过滤表中的EndpointName属性引用<client>片段内定义的端点。
使用WCF,你还可以基于其他条件过滤消息。比如,你可以指定EndpointAddress以定义一个EndpointAddressMessageFilter。如果你希望基于消息体的内容执行过滤,你可以通过XPath创建一个XPathMessageFilter对象,此时flterData属性用于定义消息中数据的路径并且该属性的值对应一个Xpath表达式。
更过关于其他过滤类型的详细信息,请参考http://msdn.microsoft.com/en-us/library/system.servicemodel.routing.configuration.filtertype.aspx).
16. 重新生成项目。
现在你可以测试RoutingService宿主程序和配置。但是,为了演示消息被正确的路由到两个ShoppingCartService服务端点,你将配置ShoppingCartHost程序,并添加一个服务行为已显示每条接收和发送消息的动作和地址。
练习:测试RoutingService服务
1. 在ShoppingCartHost项目中,引用MessageInspector组件。
2. 使用WCF服务配置管理器打开ShoppingCartHost项目的App.config文件。在配置面板,展开高级文件夹,展开扩展,然后点击行为元素扩展。
3. 在右下面板,点击创建新的行为元素扩展。在扩展配置元素编辑器中,在名字文本框处,输入messageInspector
添加类型字段,然后该字段后的省略号按钮,在行为扩展类型浏览对话框中,选择Chpater14文件夹,然后点击MessageInspector组件,然后点击打开按钮。在行为扩展类型类型对话框中,点击MessageInspector.ShoppingCartBehaviroExtensionElement,然后点击打开按钮。
在扩展配置元素编辑对话框中,点击确认按钮。
4. 在配置面板,展开高级文件夹下的服务行为,然后点击DurabelServiceBehavior行为。在右边面板中,点击添加按钮,然后添加messageInspector行为元素至DurableServiceBehavior行为。
5. 保存配置文件并退出WCF服务配置管理器
6. 在解决方案浏览器窗口,在ShoppingCart方案上点击右键,然后设置方案的启动项目。把StaticRouter项目添加到启动项目组中。然后点击确认按钮
7. 在非调适模式下启动解决方案。Shopping Cart GUI客户端窗口将出现,同事还会出现一个ShoppingCartHost控制台程序和StaticRouter控制台程序。
8. 在Shopping Cart GUI窗口中的产品编码处输入SA-M198,然后点击添加按钮。接着继续添加另外一个产品WH-H098到购物车中。最后点击结算按钮。
客户端程序将得到与我们之前练习一样的结果。
9. 切换到ShoppingCartHost项目的控制台窗口。你将看到消息探测器所显示的消息。确认所有AddItemToCart请求都发送至在9010端口侦听的服务;而Chekcout消息发送至在9020端口侦听的服务。
10. 关闭Shopping Cart GUI窗口,分别在控制台窗口中按ENTER键关闭服务寄宿窗口和StaticRouter窗口。
总结
在本章,你已经了解到如何通过配置服务发现以从服务的实现中分离服务的地址;此外你还学习到WCF所支持的三种常见的服务发现模式:ad hoc, 声明和托管。
你还仔细地研究了如何实现路由WCF服务。你已经了解到WCF服务的运行时如何确定怎么处理请求消息。接收到消息的通道分发器逐个查询其端点分发器对象。一个端点分发器对外公开AddressFilter和ContractFilter属性,ChannelDispatcher对象使用这两个属性以发现该端点分发器是否可接收消息。被通道分发器选中的端点分发器开始处理消息并调用服务对应的方法。你可以通过提供自己的AddressFilter和ContractFilter对象,以及实现IDispatchOperationSelector接口;以实现自定义端点分发器接收和处理消息的方式。
此外,你还看到如何定义一个通用的WCF服务,该服务可以作为其他服务的路由器,该路由服务实现了一个方法,该方法可以接收任何消息并推送消息到可以处理这些消息的服务。
最后,你了解到如何使用和配置RoutingService类以实现基于在配置文件中的定义的信息路由消息。