最近,我正在探索某种方法来记录我的 WCF 服务处理的任何请求/响应。
在此之前,我对跟踪选项有一些不好的经验。现在,我还不知道如何从跟踪中获取实际的响应和请求(我尝试了 svctraceviewer 工具,但它没有得到对我有意义的东西)。即便如此,生成的跟踪文件也已损坏(其中包含一些意想不到的字符)。
大约三四天前,我了解了消息检查器技术。我阅读了本手册并在我的其他项目中实现了客户端消息检查器。实际上,我可以看到我的 wcf 客户端发送的任何请求以及该请求的其他服务响应。
我希望做另一侧日志记录同样容易(例如从客户端获取服务请求和服务器对它们的响应)。但我不冷。以下是详细信息:
public class LogMessageBehavior : IEndpointBehavior
{
public LogMessageBehavior()
{ }
public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{ }
public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
{
throw new NotImplementedException();
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
{
LogMessageInspector inspector = new LogMessageInspector();
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(inspector);
}
public void Validate(ServiceEndpoint endpoint)
{
}
}
public class LogMessageBehaviorExtensionElement : BehaviorExtensionElement
{
public LogMessageBehaviorExtensionElement() { }
public override Type BehaviorType
{
get
{
return typeof(LogMessageBehavior);
}
}
protected override object CreateBehavior()
{
return new LogMessageBehavior();
}
}
public class LogMessageInspector : IDispatchMessageInspector
{
object IDispatchMessageInspector.AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
{
throw new NotImplementedException();
}
void IDispatchMessageInspector.BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
throw new NotImplementedException();
}
}
几乎所有代码都使用 NotImplementedException 存根,但我在每个方法和属性上都设置了断点。此外,我将讲述他们是如何被击中的。
App.config
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<extensions>
<behaviorExtensions>
<add name="LogMessage" type="MyService.Extensions.LogMessageBehaviorExtensionElement, MyServiceApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</behaviorExtensions>
</extensions>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="True"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="LogMessageEndpointBehavior">
<LogMessage />
</behavior>
</endpointBehaviors>
</behaviors>
<diagnostics>
<messageLogging
logEntireMessage="true"
logMalformedMessages="true"
logMessagesAtServiceLevel="true"
logMessagesAtTransportLevel="true"
maxMessagesToLog="3000"
maxSizeOfMessageToLog="20000"/>
</diagnostics>
<!-- omitted for brewity -->
<services>
<service name="MyService">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8733/"/>
</baseAddresses>
</host>
<endpoint address="MyServiceAddress" binding="basicHttpBinding" bindingConfiguration="MyService" contract="MyService" name="MyService" behaviorConfiguration="LogMessageEndpointBehavior">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="MyService" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="Transport">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
<!-- omitted for brewity -->
</basicHttpBinding>
</bindings>
</system.serviceModel>
<system.diagnostics>
<sources>
<source name="System.ServiceModel.MessageLogging">
<listeners>
<add name="messages"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData="C:\messages.svclog" />
</listeners>
</source>
</sources>
</system.diagnostics>
</configuration>
以下是该服务的安装方式:
ServiceHost myserviceHost = new ServiceHost(typeof(MyService), new Uri(Environment.bindAddress));
myserviceHost.Open();
Console.WriteLine(myserviceHost.BaseAddresses[0]);
Console.ReadLine();
服务等级没有任何特别之处。
那么,这个建筑是如何运作的。正如我之前提到的,我在每个方法和属性中都设置了断点。在我开始调试后,我们按以下顺序获得断点命中:
1. public LogMessageBehaviorExtensionElement() { }
2. get { return typeof(LogMessageBehavior); }
3. get { return typeof(LogMessageBehavior); } (again)
4. get { return typeof(LogMessageBehavior); } (again)
5. get { return typeof(LogMessageBehavior); } (again)
好的,让我们尝试向服务发送一些东西,看看它是如何反应的。所以我发送了一些请求(使用 WSDL 生成)来处理http://localhost:8733/
并获得有效的响应。我为此使用了 SoapUI。VS 中没有任何断点活动!消息检查器不起作用。服务方法命中的断点,它表明该方法在没有消息检查器的情况下确实有效。
我还尝试使用此代码附加行为来设置服务(因此没有在 app.config 中指定行为):
ServiceHost myserviceHost = new ServiceHost(typeof(MyService), new Uri(Environment.bindAddress));
myserviceHost.Open();
foreach (ServiceEndpoint endpoint in myserviceHost.Description.Endpoints)
{
endpoint.Behaviors.Add(new LogMessageBehavior());
}
Console.WriteLine(myserviceHost.BaseAddresses[0]);
Console.ReadLine();
在这个选项中,我们得到了这个断点命中的顺序:
1. public LogMessageBehavior() { }
这就对了。而且也没有任何检查员在发送服务请求方面的活动。
那么我怎样才能让它工作呢?