前面的几篇文章,我们学习了怎么开发WCF应用程序与服务,也学习了如何进行WCF的配置。对于Web Service与WCF服务应用,服务端与客户端的通信是通过收发SOAP Message进行,我们如何有效而快速的获取通信信息呢?这就是本文要介绍的一个工具。
一、TcpTrace实现的基本原理
在对Web Service和WCF进行调试时,可以使用Soap Trace 工具对Soap Message进行深入捕获并进行分析。经常使用的工具有TcpTrace与Microsoft Soap Toolkit中的Soap Trace Utility。
对于希望对WCF的消息交换有一个深层次了解的开发者来说,TcpTracer绝对是一个不可多得好工具。我们将TcpTracer置于服务和服务代理之间,TcpTracer会帮助我们接获、显示和转发流经他的消息。
首先来讲讲TcpTrace实现的基本原理。说简单点,TcpTracer就是一个监听/转发器(Listening/Forwarding),就是一个路由器。当启动的时候,我们需要设置两个端口:监听端口(Listening Port)和目的主机(Destination Server)与目的端口(Destination Port),然后TcpTracer就会在本机的监听端口进行网络监听。一旦有针对该监听端口的请求抵达,他会截获整个请求的消息,并将整个消息显示到消息面板上。随后,TcpTracer会将该消息原封不动地转发给目的主机与目的端口。在另一方面,从目的主机与目的端口发送给原端口的消息,也同样被TcpTracer截获、显示和转发。 说白了就是把要发的消息先给我们查看和备份,再转发出去。
接下来我们我们通过下面的步骤演示如何通过TcpTracer在WCF中进行消息的路由。
1) 为了演示TcpTracer在WCF中的应用,还是用我们前面做的书籍查询示例的WCF服务应用(BookService),具体参见WCF学习之旅——第一个WCF示例(一)与WCF学习之旅—WCF第二个示例(五)。
2) 示例中的终结点的地址为:http://127.0.0.1:8888/BookService(Port为8888)。
3) 同时这个服务端的配置文件信息如下:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework
, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" /> </configSections>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
<system.serviceModel>
<diagnostics>
<messageLogging logEntireMessage="true" logKnownPii="false" logMalformedMessages="true"
logMessagesAtServiceLevel="true" logMessagesAtTransportLevel="true" />
<endToEndTracing propagateActivity="true" activityTracing="true" messageFlowTracing="true" />
</diagnostics>
<behaviors>
<serviceBehaviors> <behavior name="metadataBehavior">
<serviceMetadata httpGetEnabled="true" httpGetUrl="http://127.0.0.1:8888/BookService/metadata" />
<serviceDebug includeExceptionDetailInFaults="True" /> </behavior>
</serviceBehaviors>
</behaviors>
<services> <service behaviorConfiguration="metadataBehavior" name="SCF.WcfService.BookService">
<endpoint address="http://127.0.0.1:8888/BookService" binding="wsHttpBinding"
contract="SCF.Contracts.IBookService" /> </service>
</services>
</system.serviceModel>
<startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<system.diagnostics>
<sources>
<source name="System.ServiceModel" switchValue="Warning" propagateActivity="true">
<listeners>
<add name="xml" />
</listeners>
</source>
</sources>
<sharedListeners>
<add name="xml" type="System.Diagnostics.XmlWriterTraceListener" initializeData="D:\wcf.svclog" />
</sharedListeners>
</system.diagnostics>
</configuration>
4) 客户端的配置信息如下:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IBookService" />
<binding name="WSHttpBinding_IBookService1" />
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://127.0.0.1:8888/BookService" binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IBookService" contract="SCF.Contracts.IBookService"
name="WSHttpBinding_IBookService">
<identity>
<userPrincipalName value="DEVELOPER\Administrator" /> </identity>
</endpoint>
<endpoint address="http://127.0.0.1:8888/BookService" binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IBookService1" contract="BookServiceRef.IBookService" name="WSHttpBinding_IBookService1">
<identity>
<userPrincipalName value="DEVELOPER\Administrator" /> </identity>
</endpoint>
</client>
</system.serviceModel>
</configuration>
5) 但是通过上面的设置之后,实际上还是不能够进行数据的捕捉,如下图,无论如何在客户端调用WCF应用,TcpTrace是无法捕捉到任何数据的。
这是为什么呢?请往下看。
二、通过ClientViaBehavior实现基于TcpTracer的消息路由
在我们创建的WCF服务来说,整个服务访问只涉及到两方:服务(BookService)和服务的调用者(客户端)。从消息交换的角度来看,服务的调用者调用者将请求消息直接发送到服务端,计算结果也以回复消息的形式直接返回到服务的调用者。
现在我们需要将TcpTracer作为一个路由器引入到服务(BookService)和服务的调用者 (客户端)之间,那么我们需要解决的是:服务调用者发送的消息不能直接发送到服务端,而应该先发送给TcpTracer,再由TcpTracer转发给服务。我们可以通过ClientViaBehavior实现逻辑地址和物理地址的分离——逻辑地址指向最终的服务,而物理地址则指向 TcpTracer。
具体的原理如下图所示:我们将TcpTracer的监听端口(Listening Port)和目的端口(Destination port)设置成8080和8888(BookService地址所在的端口)。通过ClientViaBehavior将物理地址的端口设成 8080(TcpTracer监听端口)。
注:对于消息发送方来说,SOAP消息的To报头对应的地址由发送端的终结点地址(逻辑地址)决定。
基于上面的实现原理,我们需要修改客户端的配置, 在<system.serviceModel>/<behaviors>/<endpointBehaviors> 添加ClientViaBehavior,将viaUri的端口指定为8080:http://127.0.0.1:8080/BookService。并将该EndpointBehavior应用到终结点中。
1) 配置文件信息修改一下,如下面。请仔细比较一下面的客户端配置文件与上篇文章最后的客户端配置文件的区别:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup> <system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IBookService" />
<binding name="WSHttpBinding_IBookService1" /> </wsHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="bookServiceEndpointBehavior">
<clientVia viaUri="http://localhost:8080/BookService" /> </behavior>
</endpointBehaviors>
</behaviors>
<client>
<endpoint address="http://127.0.0.1:8888/BookService" binding="wsHttpBinding" behaviorConfiguration="bookServiceEndpointBehavior"
bindingConfiguration="WSHttpBinding_IBookService" contract="SCF.Contracts.IBookService"
name="WSHttpBinding_IBookService">
<identity>
<userPrincipalName value="DEVELOPER\Administrator" /> </identity>
</endpoint>
<endpoint address="http://127.0.0.1:8888/BookService" binding="wsHttpBinding" behaviorConfiguration="bookServiceEndpointBehavior"
bindingConfiguration="WSHttpBinding_IBookService1" contract="BookServiceRef.IBookService"
name="WSHttpBinding_IBookService1">
<identity>
<userPrincipalName value="DEVELOPER\Administrator" /> </identity>
</endpoint>
</client>
</system.serviceModel>
</configuration>
2) 经过修改保存之后,现在可以进行Soap Trace了,现在我们再次启动TcpTrace。进行如下的设置,如下图。
监听端口(Listen On Port#):可以*设置,但是不能够与服务的端口重合,并且该端口还需要在客户端注册。在这里设置成8080
目标端口(Destination Port #):服务端口。在这里设置成8888。
3) 先运行Hosting程序,然后运行WinClient,在WinClient中发起请求,这时请求消息和回复消息将会显示到TcpTracer的消息显示面板中,如下图所示:
4) 我们还可以通过日志,把信息记录下来,记录日志的配置如下图。
5) 当关闭tcpTrace时相应的内容被记录到我们指定的Log文件中: