WCF调试和内部机制
1. 客户端跟踪
了解.NET的Tracing机制可以知道,它主要由Source-Switch,Filter-Listener架构组成。跟踪也可在文件app.config中配置。
以一个典型客户端的配置文件格式为例:
<configuration>
<system.diagnostics>
<sources>
<source name="System.ServiceModel" ... propagateActivity ="true/false">...</source> if activity crosses boundary
<source name="System.ServiceModel.MessageLogging"
switchValue="Information"> source及其switch
<listeners> 为这个source添加listener
<add name="log" type="System.Diagnostics.XmlWriterTraceListener"
initializeData="Traces.svclog" />
</listeners>
</source>
</sources>
<sharedListeners name="…"> 也对为多个source配置共享的listener,使用只要add name引用即可
</sharedListeners>
<trace autoflush="true" /> 每次打印直接输出(此处到文件)而不缓冲
</system.diagnostics>
<system.serviceModel>
<diagnostics>
<messageLogging
logEntireMessage="true"
logMalformedMessages="false"
logMessagesAtServiceLevel="true" 记录服务级的消息
logMessagesAtTransportLevel="false" 记录传输级的消息
maxMessagesToLog="3000"
maxSizeOfMessageToLog="2000">
<filters> filter和messageLogging采用WCF特有的设置
<add nodeQuota="10" (可选,设置匹配过程中最大搜索节点数)
xmlns:soap=" http://www.w3.org/2003/05/soap-envelope"
xmlns:a=" http://www.w3.org/2005/08/addressing" >
/soap:Envelope/soap:Header/a:Action[
starts-with(text(),' http://schemas.xmlsoap.org')] 设置XPath用于匹配
</add>
</filters>
</messageLogging>
</diagnostics>
… system.serviceModel内客户端的其他配置
2. 端到端跟踪
活动(Activities)是WCF端到端跟踪中基本信息单元。
活动不是对象,而是WCF进行处理活动的一些节点。活动一般可以解释为:当X正在发生时,跟踪就产生。
为了实现端到端跟踪,在client和service的source的propagateActivity属性均需设置为true,这样一个跟踪就可以产生一个转移跟踪(Trace Transfer)。
用Guid.NewGuid()创建一个Guid对象
Trace.CorrelationManager.ActivityId用来设置当前活动的GUID。
ts.TraceTransfer(int eventId, string message, Guid relatedActivityId)用来发生转移,relatedActivityId为转入时为新的GUID,转回时为原GUID。
3. WCF扩展和检视
3.1 参数检视
接口:
interface IParameterInspector {
object BeforeCall(string operationName, object[] inputs);
void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState);
}
客户端:
BeforeCall在参数序列化之前发生;AfterCall在消息返回参数反序列化之后发生。当参数不正确,需要阻止传递时,应抛出FaultException。
在proxy创建后,用proxy.Endpoint.Contract.Operations[0].Behaviors.Add(new XXXInspector())安装。
服务端:
BeforeCall在消息到达,参数反序列化后发生;AfterCall在处理完成消息返回,参数序列化之前发生。
安装通过实现一个实现IOperationBehavior的Attribute完成,其中接口要求实现以下方法:
void ApplyDispatcherBehavior(OperationDescription operationDescription, DispatchDescription dispatchDescription)
(服务端设置)通常在其中安装检视器:dispatchOperation.ParameterInspectors.Add(new XXXInspector())
void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
(客户端设置,在服务端不必实现)
void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
void Validate(OperationDescription operationDescription)
客户端:
interface IClientMessageInspector {
object BeforeSendRequest(ref Message request, IClientChannel channel);
// 在请求消息送出前发生,返回correlationState,在AfterReceiveReply中出现
void AfterReceiveReply(ref Message reply, object correlationState);
// 在响应消息受到后发生
}
服务端:
interface IDispatchMessageInspector {
object AfterReceiveRequest(ref Message request, IClientChannel channel,
InstanceContext instanceContext);
// 在请求消息受到发生,instanceContext包含service信息,返回correlationState,在BeforeSendReply中出现
void BeforeSendReply(ref Message reply, object correlationState);
// 在响应消息发出前发生
}
消息Message是流式对象,其状态MessageState包含Created, Written, Read, Copied, Closed,在Created状态下可以处理其消息体,只能处理一次,其后就进入Written, Read或Copied态。因此在上述消息检视中必须先复制再使用,以上述request为例:
MessageBuffer buffer = request.CreateBufferedCopy(Int32.MaxValue);
T body = request.CreateMessage().GetBody<T>(); // 获得消息体可供查阅
request = buffer.CreateMessage(); // 至此request又赋予一个初始态的Message对象
装载:
实现:
interface IEndpointBehavior {
void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime);
void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher);
void AddBindingParameters(ServiceEndpoint endpoint,
BindingParameterCollection bindingParameters);
void Validate(ServiceEndpoint endpoint);
}
设置:
创建继承于BehaviorExtensionElement。重载Type BehavioerType { get; }返回上述实现的Behavior的类型;重载object CreateBehavior(),返回一个新建的上述Behavior对象。
在配置文件中做如下设置(type中内容必须严格字符一致)
<system.ServiceModel> <behaviors>
<behavior name="Behavior的类名">
<messageLogger />
…
</behaviors>
<extensions> <behaviorExtensions>
<add name="messageLogger "
type="assembly.LoggingBehaviorExtensionElement, assembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
…