4

I have a WCF REST webservice action that is called using a POST request containing a schema fixed XML content from a PHP website. There is rolled file log on the webservice traces to keep track of any errors when processing requests.

Sometimes the incoming message cannot be processed because the xml in the POST request is not valid (end element is missing for example). To understand the issue, I would like to see the source XML from the request as a raw string in my logs.

I did try implementing a IDispatchMessageInspector but any time I try to access the request body I get (rightly) an XmlException.

Adding a listener on System.ServiceModel.MessageLogging doesn't work either for this case.

Any way to achieve this ?

Ermiar
  • 1,078
  • 13
  • 20
  • One good source for WCF extensibility is the [MSDN blog of Carlos Figueira](http://blogs.msdn.com/b/carlosfigueira/archive/2011/03/14/wcf-extensibility.aspx). How do you access the message? Have you tried to implement a custom [trace listener](http://blogs.msdn.com/b/carlosfigueira/archive/2011/08/02/wcf-extensibility-system-diagnostic-tracing.aspx)? – Jérémie Bertrand Sep 17 '15 at 14:25
  • @JérémieBertrand : I have a custom trace listener that I use to redirect the WCF trace to my rolling file appender (which is provided by log4Net). That is not the issue, when I try to log the request, all I have is that the message is not XML valid. No way to retrieve a string representation of the not valid XML message to see what is wrong with it. – Ermiar Sep 17 '15 at 14:30
  • A solution could be to implement a custom [Message Formatter](http://blogs.msdn.com/b/carlosfigueira/archive/2011/05/03/wcf-extensibility-message-formatters.aspx), the use of WebContentFormat.Raw should preserve the message. – Jérémie Bertrand Sep 17 '15 at 14:47

1 Answers1

3

I finally used reflection as described in this post.

My problem was that I didn't have the internal type to do this properly. With ILSpy I found out wich type I needed.

I do now the logging with a IDispatchMessageInspector like this :

 public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
 {
     // Loggin incoming message
     log.WriteLine("Incoming message :");

     MessageEncoder encoder = OperationContext.Current.IncomingMessageProperties.Encoder;
     string contentType = encoder.ContentType;
     Match characterSetMatch = re.Match(contentType);

     if (!characterSetMatch.Success)
     {
         log.WriteLine("Failed to extract character set from request content type: " + contentType);
     }
     else
     {
         try
         {    
             Type bufferedMessageType = typeof(Message).Assembly.GetType("System.ServiceModel.Channels.BufferedMessage");
             Type bufferedMessageData = typeof(Message).Assembly.GetType("System.ServiceModel.Channels.BufferedMessageData");

             string characterSet = characterSetMatch.Groups[0].Value;

             object messageData = bufferedMessageType.InvokeMember("MessageData",
                           BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetProperty,
                           null, request, null);

             object buffer = bufferedMessageData.InvokeMember("Buffer",
                                        BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty,
                                        null, messageData, null);


             ArraySegment<byte> arrayBuffer = (ArraySegment<byte>)buffer;
             Encoding encoding = Encoding.GetEncoding(characterSet);

             string requestMessage = encoding.GetString(arrayBuffer.Array, arrayBuffer.Offset, arrayBuffer.Count);

             log.WriteLine(requestMessage);
         }
         catch(Exception e)
         {
             log.WriteLine("Error in decoding incoming message");
             log.WriteException(e);
         }

     }

     return null;
 }

The Regex I use to get the content type was found here :

Regex re = new Regex("(?<=charset=)[^;]*");
Community
  • 1
  • 1
Ermiar
  • 1,078
  • 13
  • 20