1

最近,我正在探索某种方法来记录我的 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() { }

这就对了。而且也没有任何检查员在发送服务请求方面的活动。

那么我怎样才能让它工作呢?

4

1 回答 1

0

添加行为后尝试打开主机。它应该可以正常工作。

ServiceHost myserviceHost = new ServiceHost(typeof(MyService), new Uri(Environment.bindAddress));

foreach (ServiceEndpoint endpoint in myserviceHost.Description.Endpoints)
{
   endpoint.Behaviors.Add(new LogMessageBehavior());
}

myserviceHost.Open();

Console.WriteLine(myserviceHost.BaseAddresses[0]);
Console.ReadLine();
于 2013-04-29T05:15:42.870 回答