WCF 4.0 之 Routing Service

来源:互联网 发布:淘宝店铺装修不能编辑 编辑:程序博客网 时间:2024/05/23 18:52

现在WCF 4.0内置了路由服务——System.ServiceModel.Routing.RoutingService,可以在 System.ServiceModel.Routing.dll 中找到。
比如下面的场景会使用到路由服务:只暴露一个外部公开的 Endpoint 映射到内部的多个的服务上。

路由服务使用的消息筛选器提供常用消息选择功能,例如,终结点的名称、SOAP 操作或消息已发送到的地址或地址前缀。也可以使用AND 条件连接筛选器,这样,仅当消息同时与两个筛选器匹配时,才会将消息路由至某个终结点。此外,还可以通过创建自己的 MessageFilter 实现来创建自定义筛选器。(MSDN:消息筛选器)

下面做一个实例来看看 RoutingService 该如何配置。
1. Console Hosting Request/Reply WCF Service Routing (示例代码下载)
(1) 创建一个普通的Wcf Service Library (使用Console Hosting)
Console Host

 
  1. static void Main(string[] args) 
  2.     using (var host = new ServiceHost(typeof(WcfSvcLib.Service1))) 
  3.     { 
  4.         host.Open(); 
  5.         Console.WriteLine("WcfService1 is started..............."); 
  6.         Console.Read(); 
  7.     } 
app.config
  1. <system.serviceModel> 
  2.   <services> 
  3.     <servicename="WcfSvcLib.Service1"behaviorConfiguration="WcfSvcLib.Service1Behavior"> 
  4.       <host> 
  5.         <baseAddresses> 
  6.           <addbaseAddress="http://localhost:20000/WcfRoutingServiceTest/Service1/"/> 
  7.         </baseAddresses> 
  8.       </host> 
  9.       <endpointname="WcfService1"address=""binding="wsHttpBinding"contract="WcfSvcLib.IService1"> 
  10.         <identity> 
  11.           <dnsvalue="localhost"/> 
  12.         </identity> 
  13.       </endpoint> 
  14.       <endpointaddress="mex"binding="mexHttpBinding"contract="IMetadataExchange"/> 
  15.     </service> 
  16.   </services> 
  17.  
  18.   <behaviors> 
  19.     <serviceBehaviors> 
  20.       <behaviorname="WcfSvcLib.Service1Behavior"> 
  21.         <serviceMetadatahttpGetEnabled="True"/> 
  22.         <serviceDebugincludeExceptionDetailInFaults="False"/> 
  23.       </behavior> 
  24.     </serviceBehaviors> 
  25.   </behaviors>     
  26. </system.serviceModel> 

为了测试,Service1 使用的是 PerSession,当 Service1 被第一次调用时,服务端构造一次 Service1 实例。并在之后的调用中保持该 Session。
SetName 将保存一个值,GetName 则取出该值。

 
  1. namespace WcfSvcLib 
  2.     [ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)] 
  3.     public class Service1 : IService1 
  4.     { 
  5.  
  6.         private string _name =""
  7.  
  8.         public Service1() 
  9.         { 
  10.             Console.WriteLine("Service1 ctor: " + Guid.NewGuid().ToString()); 
  11.         } 
  12.  
  13.         public string GetData(int value) 
  14.         { 
  15.             return string.Format("You entered: {0}", value); 
  16.         } 
  17.  
  18.         public void SetName(string name) 
  19.         { 
  20.             _name = name; 
  21.         } 
  22.  
  23.         public string GetName() 
  24.         { 
  25.             return _name; 
  26.         } 
  27.     } 
(2) 创建 Wcf Routing Service Host (使用Console Hosting)
首先添加 System.ServiceModel.Routing.dll,  using System.ServiceModel.Routing;
  1. static void Main(string[] args) 
  2.     using (var host = new ServiceHost(typeof(RoutingService))) 
  3.     { 
  4.         try 
  5.         { 
  6.             host.Open(); 
  7.             Console.WriteLine("RoutingService is started..............."); 
  8.             Console.Read(); 
  9.         } 
  10.         catch (Exception ex) 
  11.         { 
  12.             Console.WriteLine(ex.Message); 
  13.         } 
  14.         Console.Read(); 
  15.     } 

重点在于 RoutingService 的配置文件,详细参看代码中的注释说明。

 

  1. <?xmlversion="1.0"?> 
  2. <configuration> 
  3.  
  4.   <system.web> 
  5.     <compilationdebug="true"/> 
  6.   </system.web> 
  7.    
  8.   <system.serviceModel> 
  9.     <services> 
  10.       <!-- 定义 Routing Service 的地址(baseAddress+endpoint address), 
  11.              绑定(wsHttpBinding),契约(System.ServiceModel.Routing.IRequestReplyRouter) --> 
  12.       <!-- 注意:Routing Service 的契约必须和被路由服务的模型吻合比如:  
  13.              Request/Reply 模式,OneWay 模式,或者是 Duplex 模式。这里是 Request/Reply 模式 --> 
  14.       <servicename="System.ServiceModel.Routing.RoutingService"behaviorConfiguration="MyRoutedServBehavior"> 
  15.         <host> 
  16.           <baseAddresses> 
  17.             <addbaseAddress="http://localhost:20002/WcfRoutingServiceTest/router"/> 
  18.           </baseAddresses> 
  19.         </host> 
  20.         <endpointaddress="service1"binding="wsHttpBinding"name="MyRoutingEndpoint"contract="System.ServiceModel.Routing.IRequestReplyRouter"/> 
  21.       </service> 
  22.     </services> 
  23.    
  24.     <!-- 在 serviceBehavior 中加入了 routing 配置节,指明使用的 filterTableName --> 
  25.     <behaviors> 
  26.       <serviceBehaviors> 
  27.         <behaviorname="MyRoutedServBehavior"> 
  28.           <serviceMetadatahttpGetEnabled="True"/> 
  29.           <serviceDebugincludeExceptionDetailInFaults="True"/> 
  30.           <routingfilterTableName="ServiceRouterTable"/> 
  31.         </behavior> 
  32.       </serviceBehaviors> 
  33.     </behaviors> 
  34.  
  35.     <routing> 
  36.       <!-- filterTable 中配置了 filter 和 client endpoint 的映射关系 --> 
  37.       <!-- 注意:当使用 Request/Reply 模型时,filterTable 里不能有多个 Endpoint  
  38.           (详细参看:http://msdn.microsoft.com/zh-cn/library/ee816891.aspx 的多播一节)--> 
  39.       <filterTables> 
  40.         <filterTablename="ServiceRouterTable"> 
  41.           <addfilterName="ServiceRouter_Filter1"endpointName="WcfService1"/> 
  42.           <!-- 
  43.           <addfilterName="ServiceRouter_Filter2"endpointName="WcfService1"/> 
  44.           <addfilterName="ServiceRouter_Filter3"endpointName="WcfService1"/> 
  45.           --> 
  46.         </filterTable> 
  47.       </filterTables> 
  48.        
  49.       <filters> 
  50.         <!-- 配置 filter:--> 
  51.         <!-- filterType 有:MatchAll, Action, EndpointAddress, EndpointAddressPrefix, EndpointName, XPath, Custom, And--> 
  52.         <!-- (1) MatchAll 时,filterData 就无视了,直接转发给真实的 Endpoint --> 
  53.         <!-- (2) Action 时,filterData 里填写的内容应该是 "协议://Namespace(注1)/ServiceContractName/OperationContractName" --> 
  54.         <!-- (3) EndpointAddress,filterData 里填写的某服务的URL,比如:"http://<主机名>/vdir/s.svc/b"--> 
  55.         <!-- (4) EndpointAddressPrefix, 和(3)EndpointAddress类似,顾名思义地址前缀匹配,比如:""http://<主机名>/vdir/s.svc"--> 
  56.         <!-- (5) EndpointName, 比写全地址更灵活且不容易出错(service 配置节里的 EndpoingName) --> 
  57.         <!-- (6) XPath, 功能较上面更为强大,通过对 soap 消息的 XPath 定义匹配 --> 
  58.         <!-- (7) Custom, 自定义过滤器通过继承:CustomAssembly.MyCustomMsgFilter MessageFilter 重写 Match 方法实现 --> 
  59.         <!-- (8) And 不直接筛选消息中的值,而是通过它组合两个其他筛选器来创建 AND 条件 --> 
  60.         <!--     例如:<filter name="and1" filterType="And" filter1="address1" filter2="action1" /> --> 
  61.         <filtername="ServiceRouter_Filter1"filterType="MatchAll"/> 
  62.         <!-- 
  63.         <filtername="ServiceRouter_Filter2"filterType="Action"filterData="http://tempuri.org/IService1/GetName"/> 
  64.         <filtername="ServiceRouter_Filter3"filterType="Action"filterData="http://tempuri.org/IService1/SetName"/> 
  65.         --> 
  66.       </filters> 
  67.     </routing> 
  68.  
  69.     <!-- client 配置节配置了路由服务要转发的真实服务地址 --> 
  70.     <client> 
  71.       <endpoint 
  72.              name="WcfService1"binding="wsHttpBinding" 
  73.              address="http://localhost:20000/WcfRoutingServiceTest/Service1/" 
  74.              contract="*"> 
  75.       </endpoint> 
  76.     </client> 
  77.   </system.serviceModel> 
  78.  
  79. <startup><supportedRuntimeversion="v4.0"sku=".NETFramework,Version=v4.0"/></startup></configuration> 
(3) 创建客户端应用
首先是客户端代理的生成,通过 Wcf Routing Service 好像没有办法能访问到真实服务的wsdl,
因此我的做法是先利用真实服务的wsdl生成代理,然后修改客户端配置文件
比如这个例子中真实服务地址是:http://localhost:20000/WcfRoutingServiceTest/Service1
Wcf Routing Service的地址是:    http://localhost:20002/WcfRoutingServiceTest/router/service1
修改后的客户端配置如下:
 
  1. <?xmlversion="1.0"encoding="utf-8"?> 
  2. <configuration> 
  3.     <system.serviceModel> 
  4.         <client> 
  5.             <endpointaddress="http://localhost:20002/WcfRoutingServiceTest/router/service1" 
  6.                 binding="wsHttpBinding"contract="WcfService1.IService1"name="WcfService1"> 
  7.                 <identity> 
  8.                     <dnsvalue="localhost"/> 
  9.                 </identity> 
  10.             </endpoint> 
  11.         </client> 
  12.     </system.serviceModel> 
  13. </configuration> 
客户端调用:
 
  1. static void Main(string[] args) 
  2.     using (var client = new WcfService1.Service1Client()) 
  3.     { 
  4.         var result = client.GetData(300); 
  5.         Console.WriteLine(result); 
  6.         result = client.GetData(200); 
  7.         Console.WriteLine(result); 
  8.         result = client.GetData(100); 
  9.         Console.WriteLine(result); 
  10.  
  11.         client.SetName("test"); 
  12.         Console.WriteLine(client.GetName()); 
  13.  
  14.         Console.Read(); 
  15.     } 
(4) 运行

运行结果显示,client -> Routing Service -> Wcf Service1 注意当PerSession时,如果在RoutingService 每个filter 对于 WcfService1 都是独立的Session。
http://topic.csdn.net/u/20111005/15/69a4c0b8-63ab-4528-a520-6a8568ee17d3.html

----------------------------- 分割线 ----------------------------

2. IIS Hosting Request/Reply WCF Service Routing(示例代码下载)
当使用IIS Hosting时,我们创建的 WCF 工程模板就需要改为 Wcf Service Application了。下面介绍如何配置 Wcf Service Application 中的 Routing Service
这次需要实现的是在一个 Routing Service 中路由多个不同地址的 Wcf Service (如文章开头的图片所示)
(1) Solution Overview

其中:
WcfRoutingService : http://localhost:20001/RoutingService.svc
WcfService1 :          http://localhost:20002/Service1.svc
WcfService2:         http://localhost:20003/Service1.svc

(2) 配置 WcfRoutingService
因为 WcfRoutingService 里没有任何 svc 文件,这里利用了 WCF 4.0 的无 svc 文件激活服务的新特性:

  1. <serviceHostingEnvironmentmultipleSiteBindingsEnabled="true"> 
  2.   <serviceActivations> 
  3.     <addrelativeAddress="RoutingService.svc" 
  4.          service="System.ServiceModel.Routing.RoutingService, 
  5.                       System.ServiceModel.Routing, version=4.0.0.0, Culture=neutral
  6.                       PublicKeyToken=31bf3856ad364e35/> 
  7.   </serviceActivations> 
  8. </serviceHostingEnvironment> 
另外,上面已经提到对于 WCF Request/Reply 模型的 filterTable 不允许多播,那么在 Routing Service 里,需要配置响应个数的 Endpoint
完整配置如下:
  1. <?xmlversion="1.0"?> 
  2. <configuration> 
  3.  
  4.   <system.web> 
  5.     <compilationdebug="true"targetFramework="4.0"/> 
  6.   </system.web> 
  7.    
  8.   <system.serviceModel>    
  9.     <bindings> 
  10.       <wsHttpBinding> 
  11.         <bindingname="NonSecurityBinding"> 
  12.           <securitymode="None"/> 
  13.         </binding> 
  14.       </wsHttpBinding> 
  15.     </bindings> 
  16.      
  17.     <serviceHostingEnvironmentmultipleSiteBindingsEnabled="true"> 
  18.       <serviceActivations> 
  19.         <addrelativeAddress="RoutingService.svc" 
  20.              service="System.ServiceModel.Routing.RoutingService, 
  21.                           System.ServiceModel.Routing, version=4.0.0.0, Culture=neutral
  22.                           PublicKeyToken=31bf3856ad364e35/> 
  23.       </serviceActivations> 
  24.     </serviceHostingEnvironment> 
  25.      
  26.     <services> 
  27.       <servicename="System.ServiceModel.Routing.RoutingService"behaviorConfiguration="RoutingSvcBehaviorConfig"> 
  28.         <endpointaddress="service1"binding="basicHttpBinding" name="service1Endpoint"contract="System.ServiceModel.Routing.IRequestReplyRouter"/> 
  29.         <endpointaddress="service2"binding="basicHttpBinding" name="service2Endpoint"contract="System.ServiceModel.Routing.IRequestReplyRouter"/> 
  30.       </service> 
  31.     </services> 
  32.      
  33.     <behaviors> 
  34.       <serviceBehaviors> 
  35.         <behaviorname="RoutingSvcBehaviorConfig"> 
  36.           <serviceMetadatahttpGetEnabled="True"/> 
  37.           <serviceDebugincludeExceptionDetailInFaults="True"/> 
  38.           <routingfilterTableName="ServiceRoutingTable"soapProcessingEnabled="true"/> 
  39.         </behavior> 
  40.       </serviceBehaviors> 
  41.     </behaviors> 
  42.      
  43.     <routing> 
  44.       <filterTables> 
  45.         <!-- endprointName 对应上面 service/endpoint/name --> 
  46.         <filterTablename="ServiceRoutingTable"> 
  47.           <addfilterName="Service1Filter"endpointName="WcfService1"/> 
  48.           <addfilterName="Service2Filter"endpointName="WcfService2"/> 
  49.         </filterTable> 
  50.       </filterTables> 
  51.        
  52.       <filters> 
  53.         <filtername="Service1Filter"filterType="EndpointName"filterData="service1Endpoint"/> 
  54.         <filtername="Service2Filter"filterType="EndpointName"filterData="service2Endpoint"/> 
  55.       </filters> 
  56.     </routing> 
  57.  
  58.     <client> 
  59.       <endpointname="WcfService1"binding="basicHttpBinding"address="http://localhost:20002/Service1.svc"contract="*"/> 
  60.       <endpointname="WcfService2"binding="basicHttpBinding"address="http://localhost:20003/Service2.svc"contract="*"/> 
  61.     </client> 
  62.     
  63.   </system.serviceModel> 
  64.    
  65. <system.webServer> 
  66.     <modulesrunAllManagedModulesForAllRequests="true"/> 
  67.   </system.webServer> 
  68.    
  69. </configuration> 
(3) 创建客户端应用
客户端配置文件
 
  1. <?xmlversion="1.0"?> 
  2. <configuration> 
  3.     <system.serviceModel> 
  4.         <bindings> 
  5.             <basicHttpBinding> 
  6.                 <bindingname="BasicHttpBinding_IService1"/> 
  7.                 <bindingname="BasicHttpBinding_IService2"/> 
  8.                 <bindingname="service1Endpoint"/> 
  9.             </basicHttpBinding> 
  10.         </bindings> 
  11.        
  12.         <client> 
  13.             <endpointaddress="http://localhost:20001/RoutingService.svc/service1" 
  14.                 binding="basicHttpBinding"bindingConfiguration="BasicHttpBinding_IService1" 
  15.                 contract="WcfService1.IService1"name="service1Endpoint"/> 
  16.             <endpointaddress="http://localhost:20001/RoutingService.svc/service2" 
  17.                 binding="basicHttpBinding"bindingConfiguration="BasicHttpBinding_IService2" 
  18.                 contract="WcfService2.IService2"name="service2Endpoint"/> 
  19.         </client> 
  20.     </system.serviceModel> 
  21. <startup><supportedRuntimeversion="v4.0"sku=".NETFramework,Version=v4.0"/></startup></configuration> 
调用
 
  1. static void Main(string[] args) 
  2.      // Test for WcfService1 
  3.      using (var service1client = new WcfService1.Service1Client("service1Endpoint")) 
  4.      { 
  5.          var result = service1client.GetData(300); 
  6.          Console.WriteLine(result); 
  7.      } 
  8.  
  9.      // Test for WcfService2 
  10.      using (var service2client =new WcfService2.Service2Client("service2Endpoint")) 
  11.      { 
  12.          var result = service2client.GetData(100); 
  13.          Console.WriteLine(result); 
  14.      } 
  15.  
  16.      Console.Read(); 
(4) 运行


----------------------------- 分割线 ----------------------------

参考:

http://msdn.microsoft.com/zh-cn/library/ee517419.aspx

http://blogs.profitbase.com/tsenn/?p=23

http://msdn.microsoft.com/zh-cn/library/ee517425.aspx

原创粉丝点击