Search code examples
c#asp.netwcfiisasp-classic

WCF: How to log raw xml message contents manually?


I have a simple classic ASP website that calls SOAP API using WCF. For debugging I need to log XML message contents manually into separate log files.

For example, the 12/23/18_34.txt file contains the XML request that was sent at 18:34 on 12/23. I have read through many articles that log WCF XML messages and found these 2 methods.

  1. Using the MessageLogging feature.
  2. Using the IClientMessageInspector.

I could do log using the first method, but doing that I couldn't save the message contents to separate files with specific names. So I tried the second method, but it's not working and I can't find what's wrong.

As the current project is a classic ASP website and has no namespace, I am not sure how to set the value for the type attribute in the web.config file. I managed to add it by creating a separate dll file that has BehaviorExtensionElement and copy it to the current project's Bin folder.

<add name="logXmlBehavior" type="MessageLogger.MessageLoggerBehaviorExtensionElement, MessageLogger, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
public class MessageLogger : IClientMessageInspector
    {
        public void AfterReceiveReply(ref Message reply, object correlationState)
        {
            MessageBuffer buffer = reply.CreateBufferedCopy(Int32.MaxValue);
            reply = buffer.CreateMessage();

            var fileName = DateTime.Now.ToString("dd_HHmm");
            System.IO.File.WriteAllText($"C:/Logs/Symmetry/{fileName}_response.txt", buffer.CreateMessage().ToString());
        }

        public object BeforeSendRequest(ref Message request, IClientChannel channel)
        {
            MessageBuffer buffer = request.CreateBufferedCopy(Int32.MaxValue);
            request = buffer.CreateMessage();

            var fileName = DateTime.Now.ToString("dd_HHmm");
            System.IO.File.WriteAllText($"C:/Logs/Symmetry/{fileName}_post.txt", buffer.CreateMessage().ToString());
            return null;
        }
    }

This is my MessageLogger class, but it doesn't log anything. 🤕

How can I add the BehaviorExtensionElement to a classic ASP website without a separate DLL? And why is my current logger not working?

PS: The website is hosted using IIS.


Solution

  • Your code snippets seem that there is no problem. Please refer to my example.
    MessageLogger class.

        public class ClientMessageLogger : IClientMessageInspector
        {
            public void AfterReceiveReply(ref Message reply, object correlationState)
            {
                string displayText = $"the client has received the reply:\n{reply}\n";
                Console.Write(displayText);
            }
    
            public object BeforeSendRequest(ref Message request, IClientChannel channel)
            {
                string displayText = $"the client send request message:\n{request}\n";
                Console.WriteLine(displayText);
                return null;
            }
    }
    

    Endpoint Behavior to be applied on the client service endpoint.

    public class AuthBehavior : BehaviorExtensionElement, IEndpointBehavior
        {
            public override Type BehaviorType => typeof(AuthBehavior);
            public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
            {
            }
            public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
            {
                ClientMessageLogger inspector = new ClientMessageLogger();
                clientRuntime.ClientMessageInspectors.Add(inspector);
            }
            public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
            {
            }
            public void Validate(ServiceEndpoint endpoint)
            {
            }
            protected override object CreateBehavior()
            {
                return new AuthBehavior();
            }
        }
    

    Then I register the endpoint behavior in the extension section and apply it on the automatically generated client service endpoint.

        <system.serviceModel>
            <bindings>
                <basicHttpBinding>
                    <binding name="BasicHttpBinding_IService" />
                </basicHttpBinding>
            </bindings>
            <client>
              <!--apply it on the endpoint-->
                <endpoint address="http://localhost:1300/" binding="basicHttpBinding"
                    bindingConfiguration="BasicHttpBinding_IService" contract="ServiceReference1.IService"
                    name="BasicHttpBinding_IService" behaviorConfiguration="authBehavior" />
            </client>
          <behaviors>
            <endpointBehaviors>
              <behavior name="authBehavior">
                <authbehavior />
              </behavior>
            </endpointBehaviors>
          </behaviors>
          <extensions>
            <behaviorExtensions>
              <!--like yours, namespace.class,assembly-->
              <add name="authbehavior" type="Client3.AuthBehavior,Client3,Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
            </behaviorExtensions>
          </extensions>
    </system.serviceModel>
    

    Eventually, the console application properly logs the message when sending a request to the server.

    ServiceReference1.ServiceClient client = new ServiceReference1.ServiceClient();
            //client.Endpoint.EndpointBehaviors.Add(new AuthBehavior());
            try
            {
                Console.WriteLine(client.SayHello());
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
    

    Result.
    enter image description here
    Besides, I think the WCF trace also could complete this task logging the communication message. Just add the below configuration, check the mylogs.svclog file in the bin folder.

      <system.diagnostics>
        <sources>
          <source name="System.ServiceModel.MessageLogging">
            <listeners>
              <add type="System.Diagnostics.XmlWriterTraceListener" name="xmlLog" initializeData="myLogs.svclog"/>
            </listeners>
          </source>
        </sources>
      </system.diagnostics>
      <system.serviceModel>
        <bindings>
          <basicHttpBinding>
            <binding name="BasicHttpBinding_IService" />
          </basicHttpBinding>
        </bindings>
        <client>
          <endpoint address="http://10.157.13.70:1300/" binding="basicHttpBinding"
            bindingConfiguration="BasicHttpBinding_IService" contract="ServiceReference1.IService"
            name="BasicHttpBinding_IService" />
        </client>
        <diagnostics>
          <messageLogging logEntireMessage="true" logMessagesAtServiceLevel="true" logMessagesAtTransportLevel="false"/>
        </diagnostics>
      </system.serviceModel>
    

    Feel free to let me know if there is anything I can help with.