总结WCF中截获消息的几种方式(二)

上文中谈到了WCF截获消息有四种方式1) 路由法  2) 自定义绑定法  3)实现接口法 4) 跟踪诊断法,上篇文章总结WCF中截获消息的几种方式详细的阐述了前面两种,本文着重阐述后面两种实现方式

3. 接口实现法

WCF已经考虑到了开发人员想通过自定义代码截获消息的需求,在WCF中,Binding,Contract,Address是构成了EndPoint,他们是Infrastructure.而Channel是Communication的最关键部分,而Behavior则是充分体现WCF扩展灵活性的一个点,如果将上面的Endpoint与Channel是树干,那么Behavior就是树枝。树干组成了参天大树,而树枝则是对树干的点缀。如果想成为一个健壮的大树,树干必不可少,而树叶可多可少,可有可无,但树叶能影响整个大树的外观特征。在WCF中自定义了三种Behavior,他们分别是:

IEndpointBehavior

IServiceBehavior

IOperationBehavior

三种Behavior作用对象分别是:Endpoint,Service,Operation.下面看下IEndpointBehavior的定义

public interface IEndpointBehavior
{
// Methods
void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection 
    bindingParameters);
void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime);
void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher);
void Validate(ServiceEndpoint endpoint);
}
 

本文中注重讨论ApplyClientBehaviorApplyDispatchBehavior,其中ApplyClientBehavior是用于应用客户端的行为,而ApplyDispatchBehavior用于服务端行为。在ApplyClientBehavior方法中的参数ClientRuntime是扩展客户端的最重要的类,他是WCF框架提供给开发人员插入扩展客户端处理消息功能的插入点。ClientRuntime类中有一个MessageInspectors属性成员,它是客户端消息检查器的集合,WCF为客户端消息检查器提供了标准接口:IClientMessageInspector,它的定义是:

public interface IClientMessageInspector
{
// Methods
void AfterReceiveReply(ref Message reply, object correlationState);
object BeforeSendRequest(ref Message request, IClientChannel channel);
}
在消息交互过程中,客户端和服务端交互的过程如下图所示:
image 
从上图中我们可以看出,消息在客户端有两种:1)在发送消息之前 2) 接收到消息之后 这两个分别对应
IClientMessageInspector的两个接口方法BeforeSendRequest  AfterReceiveReply
ApplyDispatchBehavior的方法中的参数EndpointDispatcher中有一个属性:DispatchRuntime
ClientRuntime相对应,它也有一个MessageInspectors属性,它是服务端消息检查器的集合,WCF为服务端消息检查器
提供了一个标准接口:IDispatchMessageInspector,他的定义是:
public interface IDispatchMessageInspector
{
// Methods
object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext
    instanceContext);
void BeforeSendReply(ref Message reply, object correlationState);
}
它的两个方法对应这上图中服务中的两种消息,一种是接收请求后,另外一种是发送响应前。
通过实现IClientMessageInspector IDispatchMessageInspector 这两个接口,就能实现客户端和服务端的消息拦截
器,再通过实现自定义的Behavior,然后将自定义的Behavior添加到相应的行为限制对象上,如Endpoint,Service,
Operation上就能实现对消息的拦截。做了个demo,想查看详细代码的可以下载。
这里只给出最后的运行效果图:
服务端:
image 
客户端:
image 
采用这种方法的优点是:
1) 能适用于各种场合,比如使用诸如 HTTPS 的安全传输时。
缺点是实现比较复杂,且不能跟踪传输级别的消息
 
4. 跟踪诊断法
WCF本身也提供了管理诊断功能,由于种种原因,我们可能在设计时可能没有想到记录消息的需求,而在实际运维的时候却出
现这样的需求,因为有些问题issue的解决需要查看消息内容才能更容易的诊断。WCF也提供了缺省的功能用于满足上述需求
默认情况系,WCF不记录Message,但可以通过配置config,能实现消息记录,主要是通过
System.ServiceModel.MessageLogging。下面的代码既可以增加消息记录功能
<system.diagnostics>
<sources>
<source name="System.ServiceModel.MessageLogging">
<listeners>
<add name="messages"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData="c:\logs\messages.svclog" />
</listeners>
</source>
</sources>
</system.diagnostics>
<system.serviceModel>
<diagnostics>
<messageLogging
logEntireMessage="true"
logMalformedMessages="false"
logMessagesAtServiceLevel="true"
logMessagesAtTransportLevel="false"
maxMessagesToLog="3000"
maxSizeOfMessageToLog="2000"/>
</diagnostics>
</system.serviceModel>
简要的介绍一下上面的代码,System.Diagnostics.XmlWriterTraceListener是.net表转的跟踪侦听器,使用它,必须
通过指定initializeData来设置记录的消息保存的文件地址。
在WCF中消息记录是分级别的,基本划分为:”服务“级别,”传输“级别,”格式不正确“级别。有关这三个级别,msdn
有详细的描述,我就不再赘述。
通过此种方法,还可以通过添加消息筛选器,实现对部分的消息内容进行记录,下面的代码
<messageLogging logEntireMessage="true"
logMalformedMessages="true"
logMessagesAtServiceLevel="true"
logMessagesAtTransportLevel="true"
maxMessagesToLog="420">
<filters>
<add nodeQuota="10" xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
/soap:Envelope/soap:Header
</add>
</filters>
</messageLogging>
这段代码便是指定了只记录消息标头,这些个内容,msdn上都有,不多说了。
也做了一个诊断跟踪的示例,执行后在c盘下能找到一个messages.txt的文件。内容是:
 
<E2ETraceEvent xmlns="http://schemas.microsoft.com/2004/06/E2ETraceEvent%22><System xmlns="http://schemas.microsoft.com/2004/06/windows/eventlog/system%22><EventID>0</EventID><Type>3</Type><SubType Name="Information">0</SubType><Level>8</Level><TimeCreated SystemTime="2008-10-25T14:46:58.1093176Z" /><Source Name="System.ServiceModel.MessageLogging" /><Correlation ActivityID="{00000000-0000-0000-0000-000000000000}" /><Execution ProcessName="Jillzhang.Wcf.MessageInspectors.Trace.Host.vshost" ProcessID="4556" ThreadID="11" /><Channel/><Computer>WIN-QMIXGNBHWPE</Computer></System><ApplicationData><TraceData><DataItem><MessageLogTraceRecord Time="2008-10-25T22:46:58.1043176+08:00" Source="ServiceLevelReceiveRequest" Type="System.ServiceModel.Channels.BufferedMessage" xmlns="http://schemas.microsoft.com/2004/06/ServiceModel/Management/MessageTrace%22><s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope%22 xmlns:a="http://www.w3.org/2005/08/addressing%22><s:Header><a:Action s:mustUnderstand="1">http://tempuri.org/ICalculator/Add</a:Action><a:MessageID>urn:uuid:1ef15f49-6e38-46d3-b906-d8ed78564c89</a:MessageID><a:ReplyTo><a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address></a:ReplyTo><VsDebuggerCausalityData xmlns="http://schemas.microsoft.com/vstudio/diagnostics/servicemodelsink%22>uIDPo8masvhLEkZBvyYJpVFd168AAAAAgVozn8DAXkaGix0+tb393XpBqSmzHQxOuVyNwKQn8egACQAA</VsDebuggerCausalityData><a:To s:mustUnderstand="1">net.tcp://127.0.0.1:8023/Calculator</a:To></s:Header><s:Body><Add xmlns="http://tempuri.org/%22><a>1</a><b>2</b></Add></s:Body></s:Envelope></MessageLogTraceRecord></DataItem></TraceData></ApplicationData></E2ETraceEvent><E2ETraceEvent xmlns="http://schemas.microsoft.com/2004/06/E2ETraceEvent%22><System xmlns="http://schemas.microsoft.com/2004/06/windows/eventlog/system%22><EventID>0</EventID><Type>3</Type><SubType Name="Information">0</SubType><Level>8</Level><TimeCreated SystemTime="2008-10-25T14:46:58.1293176Z" /><Source Name="System.ServiceModel.MessageLogging" /><Correlation ActivityID="{00000000-0000-0000-0000-000000000000}" /><Execution ProcessName="Jillzhang.Wcf.MessageInspectors.Trace.Host.vshost" ProcessID="4556" ThreadID="11" /><Channel/><Computer>WIN-QMIXGNBHWPE</Computer></System><ApplicationData><TraceData><DataItem><MessageLogTraceRecord Time="2008-10-25T22:46:58.1293176+08:00" Source="ServiceLevelSendReply" Type="System.ServiceModel.Channels.BodyWriterMessage" xmlns="http://schemas.microsoft.com/2004/06/ServiceModel/Management/MessageTrace%22><s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing%22 xmlns:s="http://www.w3.org/2003/05/soap-envelope%22><s:Header><a:Action s:mustUnderstand="1">http://tempuri.org/ICalculator/AddResponse</a:Action></s:Header><s:Body><AddResponse xmlns="http://tempuri.org/%22><AddResult>3</AddResult></AddResponse></s:Body></s:Envelope></MessageLogTraceRecord></DataItem></TraceData></ApplicationData></E2ETraceEvent>
 
诊断跟踪的方式非常灵活,且获取的消息也非常详细,非常适用于生产环境。同时支持自定义诊断跟踪器。推荐使用
 完整的dmeo示例:http://files.cnblogs.com/jillzhang/Jillzhang.Wcf.MessageInspector2.rar
posted @ 2008-10-25 22:51  Robin Zhang  阅读(6095)  评论(7编辑  收藏