Click here to Skip to main content
13,044,282 members (126,648 online)
Click here to Skip to main content
Add your own
alternative version


29 bookmarked
Posted 11 Aug 2005

Extract raw SOAP Message returned from Foreign Web Service after Deserialization Failure in a Web Service

, 11 Aug 2005
Rate this:
Please Sign up or sign in to vote.
Local web service calls third party web service which returns XML data and serialization fails, the article shows how to obtain the actual SOAP message.

Capturing SOAP messages that serialization cannot handle

In my job I have to write the code which consumes third party web services. In the course of working with differing companies' web services I discovered that some of those would return invalid XML data. That data was invalid due to either from an outdated schema or had some subtle problem that would cause Microsoft's deserializer to throw an exception. Since I needed to see the data sent to me, I had to work around the de-serialization operation and access the raw SOAP message which Microsoft's code refuse to divulge to my web service. This article explains I was able to end-around Microsoft by creating a specific attribute tied to a method call that allows me to see the SOAP message before serialization and will log the message for access when needed.


  • These steps are not how I coded it, but how you should proceed with the implementation.
  • This article does not cover the whys or hows of C# web services. It only details the acquisition of SOAP data in exceptional circumstances.
  • This problem occurred in a C# web service accessing a third party web service, hence the design taken below.

Step 1: Inserting a custom attribute into the proxy code

Since we are consuming a foreign web we either have to deal with Microsoft's generated proxy code or we have to create it by hand; regardless we need to find where the invoked call returns data. That is the location where we will place our specialized attribute.

If it is a generated proxy then you will need to look in the hidden file Reference.cs which resides in the web services folder. Once found, locate the primary method that returns data. That is the location were you will need to add the attribute that will handle the leg work of getting around the de-serialization situation.

// Inside proxy class before data extraction call:
// Here is our attribute to capture 
// soap and log it for us.
public zzzResponse ProcessData(...
  object[] results = this.Invoke(...


  • If this is the generated proxy code, you will need to add the attribute every time the code is re-generated.
  • You will need to add the reference to the namespace that the attribute code resides in as shown in future steps. The build process will remind you if you forget.

Step 2: Defining custom attribute SoapExtensionAttribute

The attribute is the hook for our data logging process. Here is the class which is the attribute with the appropriate overrides.

/// <span class="code-SummaryComment"><summary>The attribute [ClientSoapLogger()] </span>
/// will appear in the data return method found in the
/// proxy code.<span class="code-SummaryComment"></summary></span>
public class ClientSoapLoggerAttribute : 
   private int m_Priority = 0;

   public override Type ExtensionType
      get { return typeof(ClientSoapLogger); }

   public override int Priority
      get { return m_Priority;  }
      set { m_Priority = value; }
} // End of class ClientSoapLoggerAttribute

Step 3: Creating the SoapExtension

The SOAP extension will work with the flow of the handling of SOAP message in an autonomous fashion. Our goal is not to damage the data stream, only to look into it for data extraction.

/// <span class="code-SummaryComment"><summary>This class handles the data </span>
/// during the differing states and 
/// does so autonomously; ie in the background 
/// without affecting standard processing..<span class="code-SummaryComment"></summary></span>
public class ClientSoapLogger : SoapExtension
   public Stream oldStream;
   public Stream newStream;

   public override object GetInitializer(
                             Type serviceType)
      return null;
   public override object GetInitializer(
                     LogicalMethodInfo methodInfo, 
                     SoapExtensionAttribute attribute)
      return null;
   public override void Initialize(object initializer)

   /// <span class="code-SummaryComment"><summary>Here is where we take a </span>
   /// dip into the stream. Due to the
   /// nature of streams if we dipped 
   /// without copying, we would damage the
   /// stream.<span class="code-SummaryComment"></summary></span>
   public override Stream ChainStream(Stream stream)
      oldStream = stream;
      newStream = new MemoryStream();
      return newStream;

   /// <span class="code-SummaryComment"><summary>With this override we can </span>
   /// access the data during different stages
   /// of processing. Logging occurs during the 
   /// before and after serialization.<span class="code-SummaryComment"></summary></span>
   public override void ProcessMessage(SoapMessage message)
         case SoapMessageStage.BeforeDeserialize: 
                                LogResponse(message); break;
         case SoapMessageStage.AfterSerialize:    
                                LogRequest(message);  break;

         // Do nothing on other states
         case SoapMessageStage.AfterDeserialize:
         case SoapMessageStage.BeforeSerialize:                    
// Class continued in step 4

Step 4: Logging the data

This is the step that really got to me. If your code is in a web service (mine was a web service calling a web service) how does one pass data between the SOAP process and the code accessing the proxy? In some situations such as ASP.NET one can put the message on the HttpContext, but that wasn't an option for my code in a web service. The below code handles the situation of a null HttpContext by placing the data in the Remoting call context.

/// <span class="code-SummaryComment"><summary>Publish out the message received </span>
/// either in the HttpContext for ASP pages
/// or publish via remoting for webservices 
/// and winform applications.<span class="code-SummaryComment"></summary></span>
public void LogResponse(SoapMessage message)

   newStream.Position = 0;

   string strSOAPresponse = 

   HttpContext hc = HttpContext.Current;

   if (hc != null)
   newStream.Position = 0;


/// <span class="code-SummaryComment"><summary>Transfer the text from the target </span>
/// stream from the current position.<span class="code-SummaryComment"></summary></span>
private String ExtractFromStream(Stream target)
   if (target != null)
      return (new StreamReader(target)).ReadToEnd();

   return "";

/// <span class="code-SummaryComment"><summary>Facilitate the copying process.</summary></span>
private void Copy(Stream from, Stream to)
   TextReader reader = new StreamReader(from);
   TextWriter writer = new StreamWriter(to);
} // End ClientSoapLogger class

Step 5: Consuming the logged data

For my web service if the incoming data was invalid, my indication was either an exception thrown by the de-serializer or simply a null return value by the data access method. At that point my code tries to do a post extract of the SOAP raw data and handles the message.

[Editor Note: Line breaks used to avoid scrolling.]

// New class outside ClientSoapLogger...

/// <span class="code-SummaryComment"><summary>Examine the soap return for possible missing </span>
/// data since the return was null.<span class="code-SummaryComment"></summary></span>
protected virtual void DiagnoseResponseProblem()
   HttpContext hc = HttpContext.Current;
   string SoapResponse = null;
   string SoapRequest  = null;

   // Post processing debugging pull out 
   // the actual soap message and debug it.
   if (hc != null)
      SoapRequest  = hc.Items["SOAPRequest"].ToString();
      SoapResponse = hc.Items["SOAPResponse"].ToString();
         SoapResponse = System.Runtime.Remoting.Messaging.
         SoapRequest  = System.Runtime.Remoting.Messaging.

      // Ignore...most likely this system does not 
      // have the remote message context setup.
      catch (System.Exception){} 


  • Let me know if there is possibly a better way or things could be improved.


This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


About the Author

Web Developer
United States United States
After finding myself with lots of time after a cataclysmic event I have turned to doing programming to help fill the hours.

You may also be interested in...


Comments and Discussions

GeneralStream was not readable Pin
GhanashyamL15-Nov-07 23:02
memberGhanashyamL15-Nov-07 23:02 
GeneralRe: Stream was not readable Pin
GhanashyamL15-Nov-07 23:38
memberGhanashyamL15-Nov-07 23:38 
GeneralRe: Stream was not readable Pin
Hardy27-Feb-08 14:18
memberHardy27-Feb-08 14:18 
Question.NET SOAP Question Pin
dramsey1128-Aug-07 4:32
memberdramsey1128-Aug-07 4:32 
GeneralBrilliant! Pin
mythilee kulkarni21-Feb-07 6:14
membermythilee kulkarni21-Feb-07 6:14 
Questionmissing method? Pin
biconix24-Aug-05 11:00
memberbiconix24-Aug-05 11:00 
AnswerRe: missing method? Pin
OmegaMan25-Aug-05 6:47
memberOmegaMan25-Aug-05 6:47 
QuestionAlternate way? Pin
bigals11-Aug-05 12:22
memberbigals11-Aug-05 12:22 
AnswerRe: Alternate way? Pin
OmegaMan25-Aug-05 6:48
memberOmegaMan25-Aug-05 6:48 
AnswerRe: Alternate way? Pin
Nermin Dibek23-Nov-05 4:42
memberNermin Dibek23-Nov-05 4:42 
GeneralRe: Alternate way? Pin
Derwisch16-Dec-05 2:38
memberDerwisch16-Dec-05 2:38 
GeneralRe: Alternate way? Pin
Nermin Dibek16-Dec-05 3:48
memberNermin Dibek16-Dec-05 3:48 
GeneralRe: Alternate way? Pin
Derwisch19-Dec-05 4:17
memberDerwisch19-Dec-05 4:17 
AnswerRe: Alternate way? Pin
Hardy27-Feb-08 13:44
memberHardy27-Feb-08 13:44 
GeneralRe: Alternate way? Pin
Jagadeesh Babu Molabanti7-Mar-09 2:16
memberJagadeesh Babu Molabanti7-Mar-09 2:16 
AnswerRe: Alternate way? Pin
KbCb22-Sep-10 7:05
memberKbCb22-Sep-10 7:05 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.170713.1 | Last Updated 11 Aug 2005
Article Copyright 2005 by OmegaMan
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid