• WCF后续之旅(13):创建一个简单的SOAP Message拦截、转发工具[下篇]


    Part I 中,我们创建了一个InterceptService,并且通过一个特殊的EndpointBehavior,ClientViaBehavior实现了message的拦截、转发功能。在本节中,我们将讨论另外一种不同的实现方式。如何说ClientViaBehavior是基于Client端的实现方式,那么我们今天讨论的是基于Service的实现方式。

    在对新的实现方式展开介绍之前,我们先来介绍一下关于逻辑地址和物理地址。

    一、逻辑地址和物理地址

    我们知道,WCF通过Endpoint进行通信:service provider将service通过一个或多个Endpoint暴露给潜在的service consumer;service consumer通过与之匹配的endpoint调用service。众所周知,Endpoint=Address+Binding+Contract,而Address代表了service的地址,解决service的寻址问题。一般来讲,我们把这个地址称为逻辑地址。而物理地址代表client端最终发送message的目标地址,以及service端实际的监听地址(Listen Address)

    • 对于client端来说:一般来说,它所访问的service的地址与message最终的发送的目标地址是一样的。但是有时候也不一定相同,比如在Part I的例子中,service的地址是http://127.0.0.1:9999/calculateservice(逻辑地址),而最终我们的message却被发送到http://127.0.0.1:8888/interceptservice(物理地址)。通过ClientViaBehavior我们可以轻易地实现物理地址与逻辑地址不同的场景。
    • 对于service端来说:一般情况下service的地址(逻辑地址)与ChannelListener监听地址(物理地址)是一样的。但是在特殊的情况下也不尽相同。他能够Endpoint的ListenUri属性,我们很容易的使用一个与逻辑地址不同的监听地址。这就是我们接下来需要讨论的问题。

    二、实现原理解析

    不同于ClientViaBehavior的解决方案,我们今天讨论的方案是通过制定InterceptService或者CalcualteService Endpoint的ListenUri来实现的。而具体的实现方案,我们又有两种不同的方式,我们先来讨论这两种方式的实现原理:

    1、方案一

    image

    如上图所示,client与一般的service的调用别无二致,通过CalculateService的逻辑地址(http://127.0.0.1:9999/calculateservice)进行访问;不过CalculateService和InterceptService的ListenAddress去互换一下:CalculateService-http://127.0.0.1:8888/interceptservice,InterceptService-http://127.0.0.1:9999/calculateservice。那么Client发送到http://127.0.0.1:9999/calculateservice的Message将会被InterceptService截获,InterceptService再将截获的Message发送到CalculateService的监听地址:http://127.0.0.1:8888/interceptservice。

    2、方案二

    image

    与方案一不同的是,CalculateService的EndpointAddress(逻辑地址)设成了InterceptService的地址:http://127.0.0.1:8888/interceptservice;而监听地址(物理地址)变成:http://127.0.0.1:9999/calculateservice。由于service的逻辑地址变成了http://127.0.0.1:8888/interceptservice,所以client端Endpoint的address也将变成该地址。很显然在这中情况下,client发送到service的message将实际发送给InterceptSerivce。InterceptSerivce对message处理完毕,把该message转发到CalculateService的监听地址:http://127.0.0.1:9999/calculateservice。

    三、具体实现

    1、方案一(Source Code从这里下载下载)

    我们需要做的仅仅是改变CaculateService和InterceptService的配置文件:

       1: <?xml version="1.0" encoding="utf-8" ?>
       2: <configuration>
       3:     <system.serviceModel>
       4:         <bindings>
       5:             <customBinding>
       6:                 <binding name="MyCustomeBinding">
       7:                     <textMessageEncoding />
       8:                     <httpTransport />
       9:                 </binding>
      10:             </customBinding>
      11:         </bindings>
      12:         <services>
      13:             <service name="Artech.MessageInterceptor.Services.CalculateService">
      14:                 <endpoint address="http://127.0.0.1:9999/calculateservice" binding="customBinding"
      15:                     bindingConfiguration="MyCustomeBinding" contract="Artech.MessageInterceptor.Contracts.ICalculate"
      16:                     listenUri="http://127.0.0.1:8888/Interceptservice" />
      17:             </service>
      18:         </services>
      19:     </system.serviceModel>
      20: </configuration>
      21:  
       1: <?xml version="1.0" encoding="utf-8" ?>
       2: <configuration>
       3:     <system.serviceModel>
       4:         <bindings>
       5:             <customBinding>
       6:                 <binding name="MyCustomBinding">
       7:                     <textMessageEncoding />
       8:                     <httpTransport manualAddressing="true" />
       9:                 </binding>
      10:             </customBinding>
      11:         </bindings>
      12:         <client>
      13:             <endpoint address="http://127.0.0.1:8888/Interceptservice" binding="customBinding"
      14:                 bindingConfiguration="MyCustomBinding" contract="Artech.MessageInterceptor.Contracts.IIntercept"
      15:                 name="calculateService" />
      16:         </client>
      17:         <services>
      18:             <service name="Artech.MessageInterceptor.Services.InterceptService">
      19:                 <endpoint address="http://127.0.0.1:8888/Interceptservice" binding="customBinding"
      20:                     bindingConfiguration="MyCustomBinding" contract="Artech.MessageInterceptor.Contracts.IIntercept"
      21:                     listenUri="http://127.0.0.1:9999/calculateservice" />
      22:             </service>
      23:         </services>
      24:     </system.serviceModel>
      25: </configuration> 
      26:  

    Manual Addressing

    可能大家已经看到了,在custombing中的httpTransport 配置项中,将manualAddressing设置为true。manualAddressing在默认的情况下为false,意为着将按照WS-Addressing的方式进行Adressing。当该属性设为false,WCF会将client端的Endpoint的Address地址写入SOAP的To header中,而将manualAddressing设为true,可以保留现有SOAP的To header中的地址,在本例中InterceptService接收到的SOAP的To address为http://127.0.0.1:9999/calculateservice,然后在<client>中的endpoint address则是http://127.0.0.1:8888/Interceptservice。如果manualAddressing = false,那么To address将会变成http://127.0.0.1:8888/Interceptservice。当该SOAP抵达CalculateService时,由于ChannelDispatcher根据两个Message Filter(Address Filter和Contract Filter)定位到对应的Endpoint。Address Filter就是根据SOAP的To address来进行筛选的,在默认的情况下,是找不到对应的Endpoint的。反之,我们manualAddressing=true,将保留SOAP的To header中的address。

    我们可以根据运行后的输出来验证这一点:

    image

    如何我们保留manualAddressing的默认值(false),那么为了让CalculateService的ChannelDispatcher能够有效地定位到对应的Endpoint,需要通过ServiceBehavior设置AddressFilterMode。(具体原理参考我的文章:WCF的中枢:Dispatcher

       1: using Artech.MessageInterceptor.Contracts;
       2: using System.ServiceModel;
       3: namespace Artech.MessageInterceptor.Services
       4: {
       5:     [ServiceBehavior(AddressFilterMode = AddressFilterMode.Any)]
       6:     public class CalculateService : ICalculate
       7:     {
       8:         #region ICalculate Members 
       9:  
      10:         public double Add(double x, double y)
      11:         {
      12:             return x + y;
      13:         } 
      14:  
      15:         #endregion
      16:     }
      17: }
      18:  

    在这种情况下再次运行我们的程序,将会发现To Header中的Address变成了http://127.0.0.1:8888/Interceptservice

    image

      2、方案二 (Source Code从这里下载)

    我们看看方案二设计的配置的改动,首先是CalculateService:

       1: <?xml version="1.0" encoding="utf-8" ?>
       2: <configuration>
       3:     <system.serviceModel>
       4:         <bindings>
       5:             <customBinding>
       6:                 <binding name="MyCustomeBinding">
       7:                     <textMessageEncoding/>
       8:                     <httpTransport />
       9:                 </binding>
      10:             </customBinding>
      11:         </bindings>
      12:         <services>
      13:             <service name="Artech.MessageInterceptor.Services.CalculateService">
      14:                 <endpoint address="http://127.0.0.1:8888/Interceptservice" binding="customBinding"
      15:                     bindingConfiguration="MyCustomeBinding" contract="Artech.MessageInterceptor.Contracts.ICalculate"
      16:                     listenUri="http://127.0.0.1:9999/calculateservice" />
      17:             </service>
      18:         </services>
      19:     </system.serviceModel>
      20: </configuration>
      21:  

    接下来是InterceptService的配置:

       1: <?xml version="1.0" encoding="utf-8" ?>
       2: <configuration>
       3:     <system.serviceModel>
       4:         <bindings>
       5:             <customBinding>
       6:                 <binding name="MyCustomBinding">
       7:                     <textMessageEncoding />
       8:                     <httpTransport manualAddressing="true" />
       9:                 </binding>
      10:             </customBinding>
      11:         </bindings>
      12:         <client>
      13:             <endpoint address="http://127.0.0.1:9999/calculateservice" binding="customBinding"
      14:                 bindingConfiguration="MyCustomBinding" contract="Artech.MessageInterceptor.Contracts.IIntercept"
      15:                 name="calculateService" />
      16:         </client>
      17:         <services>
      18:             <service name="Artech.MessageInterceptor.Services.InterceptService">
      19:                 <endpoint address="http://127.0.0.1:8888/Interceptservice" binding="customBinding"
      20:                     bindingConfiguration="MyCustomBinding" contract="Artech.MessageInterceptor.Contracts.IIntercept"/>
      21:             </service>
      22:         </services>
      23:     </system.serviceModel>
      24: </configuration> 
      25:  

    最后是Client的

       1: <?xml version="1.0" encoding="utf-8" ?>
       2: <configuration>
       3:     <system.serviceModel>
       4:         <bindings>
       5:             <customBinding>
       6:                 <binding name="MyCustomBinding">
       7:                     <textMessageEncoding />
       8:                     <httpTransport />
       9:                 </binding>
      10:             </customBinding>
      11:         </bindings>
      12:         <client>
      13:             <endpoint name="calculateservice" address="http://127.0.0.1:8888/Interceptservice" binding="customBinding" bindingConfiguration="MyCustomBinding"
      14:                 contract="Artech.MessageInterceptor.Contracts.ICalculate" />
      15:         </client>
      16:     </system.serviceModel>
      17: </configuration>

    WCF后续之旅: 
    WCF后续之旅(1): WCF是如何通过Binding进行通信的 
    WCF后续之旅(2): 如何对Channel Layer进行扩展——创建自定义Channel 
    WCF后续之旅(3): WCF Service Mode Layer 的中枢—Dispatcher 
    WCF后续之旅(4):WCF Extension Point 概览 
    WCF后续之旅(5): 通过WCF Extension实现Localization 
    WCF后续之旅(6): 通过WCF Extension实现Context信息的传递 
    WCF后续之旅(7):通过WCF Extension实现和Enterprise Library Unity Container的集成 
    WCF后续之旅(8):通过WCF Extension 实现与MS Enterprise Library Policy Injection Application Block 的集成 
    WCF后续之旅(9):通过WCF的双向通信实现Session管理[Part I] 
    WCF后续之旅(9): 通过WCF双向通信实现Session管理[Part II] 
    WCF后续之旅(10): 通过WCF Extension实现以对象池的方式创建Service Instance 
    WCF后续之旅(11): 关于并发、回调的线程关联性(Thread Affinity) 
    WCF后续之旅(12): 线程关联性(Thread Affinity)对WCF并发访问的影响 
    WCF后续之旅(13): 创建一个简单的WCF SOAP Message拦截、转发工具[上篇] 
    WCF后续之旅(13):创建一个简单的SOAP Message拦截、转发工具[下篇] 
    WCF后续之旅(14):TCP端口共享 
    WCF后续之旅(15): 逻辑地址和物理地址 
    WCF后续之旅(16): 消息是如何分发到Endpoint的--消息筛选(Message Filter) 
    WCF后续之旅(17):通过tcpTracer进行消息的路由


    作者:Artech
    出处:http://artech.cnblogs.com/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    MonkeyScript_API
    APP性能(Monkey)【启动时间、CPU、流量、电量、内存、FPS、过度渲染】
    adb基本命令 & Monkey发生随机事件命令及参数说明
    MonkeyRunner_API
    2021春招冲刺-1218 页面置换算法 | sort的原理 | 语义化标签 | 标签的继承
    2021春招冲刺-1217 线程与进程 | ES6语法 | h5新增标签
    2021春招冲刺-1216 死锁 | 箭头函数 | 内联元素 | 页面渲染
    【unity】旧世开发日志
    HTTP 与HTTPS 简单理解
    GET POST 区分
  • 原文地址:https://www.cnblogs.com/artech/p/1281755.html
Copyright © 2020-2023  润新知