April 24, 2014

I am trying to debug a code where a web service was being consumed by both .NET and Java application. I was in a scenario where I had to generate the raw request and response xml file and share it with the java developer. Usually, we can simply call the objects / methods in .net and so how can we view the raw request and response files when calling the web services. To work on this scenario, we can take advantage of System.Web.Services.Protocols.SoapExtension in .NET and create our own class by implementing the SoapExtension class.

In this example, I will develop a class - LogSoapExtension - that will implement SoapExtension and log the soap request and response xml into a log file. Basically, the current date & time and the request / response xml will logged. I have used the example on SoapExtension from MSDN site. The SoapExtention class contains a method - ProcessMessage - that needs to overridden (along with other methods) and we will override this method and check the status of the Soap message (BeforeSerialize, AfterSerialize, BeforeDeserialize, AfterDeserialize) where we can get hold of the request / response xml and log it to a file.

At the end, I will show how to register the Soap Extension in web.config file so it can be used. The good thing is no changes are necessary at the web service level or to the application that is calling the services.

Here is the code sample for the Soap Extension class.

Soap Extension
  1. using System;
  2. using System.IO;
  3. using System.Web.Services.Protocols;
  4. using System.Xml;
  5.  
  6. namespace WSTest.Helper
  7. {
  8.     public class LogSoapExtension : SoapExtension
  9.     {
  10.         private Stream oldStream;
  11.         private Stream newStream;
  12.        
  13.         public static XmlDocument XmlRequest
  14.         {
  15.             get;
  16.             set;
  17.         }
  18.  
  19.         
  20.         public static XmlDocument XmlResponse
  21.         {
  22.             get;
  23.             set;
  24.         }
  25.  
  26.         /// <summary>
  27.         /// Save SOAP request/response Stream into memory
  28.         /// </summary>
  29.         public override Stream ChainStream(Stream stream)
  30.         {
  31.             oldStream = stream;
  32.             newStream = new MemoryStream();
  33.             return newStream;
  34.         }
  35.  
  36.         public override void ProcessMessage(SoapMessage message)
  37.         {
  38.             switch (message.Stage)
  39.             {
  40.                 case SoapMessageStage.BeforeSerialize:
  41.                     break;
  42.                 case SoapMessageStage.AfterSerialize:
  43.                     XmlRequest = GetSoapEnvelope(newStream);
  44.                     CopyStream(newStream, oldStream);
  45.                     Log(XmlRequest.InnerXml);
  46.                     break;
  47.                 case SoapMessageStage.BeforeDeserialize:
  48.                     CopyStream(oldStream, newStream);
  49.                     XmlResponse = GetSoapEnvelope(newStream);
  50.                     Log(XmlResponse.InnerXml);
  51.                     break;
  52.                 case SoapMessageStage.AfterDeserialize:
  53.                     break;
  54.             }
  55.         }
  56.  
  57.         /// <summary>
  58.         /// Get XML from Soap Envelope
  59.                 /// </summary>
  60.         private XmlDocument GetSoapEnvelope(Stream stream)
  61.         {
  62.             XmlDocument xml = new XmlDocument();
  63.             stream.Position = 0;
  64.             StreamReader reader = new StreamReader(stream);
  65.             xml.LoadXml(reader.ReadToEnd());
  66.             stream.Position = 0;
  67.             return xml;
  68.         }
  69.  
  70.         
  71.         private void CopyStream(Stream from, Stream to)
  72.         {
  73.             TextReader reader = new StreamReader(from);
  74.             TextWriter writer = new StreamWriter(to);
  75.             writer.WriteLine(reader.ReadToEnd());
  76.             writer.Flush();
  77.         }
  78.  
  79.  
  80.         /// <summary>
  81.         /// Log request / response xml
  82.         /// </summary>
  83.         private void Log(string message)
  84.         {
  85.             DateTime d = DateTime.Now;
  86.             string filename = d.Year.ToString() + "-" + d.Month.ToString() + "-" + d.Day.ToString() + ".log";
  87.             string filepath = @"C:\logdata\";
  88.  
  89.             string logMessage = "\n\n" + DateTime.Now.ToString() + "\n" + message;
  90.             
  91.             if (!File.Exists(filepath + filename))                
  92.                 File.Create(filepath + filename);
  93.  
  94.             File.AppendAllText(filepath + filename, logMessage);
  95.         }
  96.      
  97.  
  98.         void Copy(Stream from, Stream to)
  99.         {
  100.             TextReader reader = new StreamReader(from);
  101.             TextWriter writer = new StreamWriter(to);
  102.             writer.WriteLine(reader.ReadToEnd());
  103.             writer.Flush();
  104.         }
  105.  
  106.  
  107.         #region InterfaceMethods
  108.         
  109.         public override object GetInitializer(LogicalMethodInfo methodInfo,
  110.             SoapExtensionAttribute attribute)
  111.         {
  112.             return null;
  113.         }
  114.         
  115.         public override object GetInitializer(Type WebServiceType)
  116.         {
  117.             return null;
  118.         }
  119.         
  120.         public override void Initialize(object initializer)
  121.         {
  122.  
  123.         }
  124.         #endregion InterfaceMethods
  125.     }
  126. }

 

Now, here is the section of the web.config file that needs to be modified to register the extension.

web.config
  1. <system.web>
  2.   <compilation debug="true" targetFramework="4.5"/>
  3.   <httpRuntime targetFramework="4.5"/>
  4. <webServices>
  5.     <soapExtensionTypes>
  6.       <add type="WSTest.Helper.LogSoapExtension, WSTest" priority="1" group="0" />
  7.     </soapExtensionTypes>
  8.   </webServices>
  9. </system.web>

 

That's it. You are done. Run your application with the extension and you will see log files created with the soap messages. Make sure the application has read / write access to the folder.

1 comments:

Anonymous said...

Hi, I am using your sample to log soap request and response but there is no log file created under c:\logdata. Below is what am doing.

- your soap extension code has been created as a class library, 'soaplogger'
- I have a .net webservice1
- web application adds service reference of webservice1
- web application adds reference of the class library 'soaplogger'
- web application's web.config file updated as below








- create c:\logdata folder but i cannot see the log files after consuming the web methods from web application.

Pls help me on this.

Thanks in advance.

Reference: Shahed Kazi at AspNetify.com