Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / MFC

Trace SOAP Request/Response XML with TraceExtension

5.00/5 (14 votes)
17 Aug 2009CPOL6 min read 205.3K   3.7K  
SOAP Request/Response XML can be logged with TraceExtension

Introduction

In one of my recent projects, I had to interact with one .NET Web Service (ASMX) from a Windows Desktop application. Now another Java application would be accessing the same Web Service. So the Java developers need a sample SOAP Request/Response XML for the Web Service. Before I start discussing the approach of logging SOAP Request-Response XML, I would like to elaborate on same basic things Web Service referencing.

What’s WSDL File and How It’s Generated?

Web Services Description Language is an XML format for describing network services as a set of endpoints operating on messages containing either document-oriented or procedure-oriented information. In a single sentence – it defines the Web Service which can be used by the clients to subscribe to the web service. In case you are not aware of generating a WSDL file of a Web Service, then follow the steps mentioned below:

  1. Type in your Web Service URL along with the ASMX file in the web browser.
  2. Then just append “?wsdl” at the end of URL, your required WSDL will be generated in the browser. So if your URL is http://localhost/HelloWorldWebService/HelloWorldService.asmx then if you type in http://localhost/HelloWorldWebService/HelloWorldService.asmx?wsdl to generate the wsdl for your web service.

How to Reference a Web Service?

This is quite easy for Visual Studio users. Using the wizard of Add Web Reference (as shown below in the images), the developer just needs to provide the URL of the Web Service. This would generate the proxy and the developer does not even need to create the WSDL separately.

Add WebReference

WebReference URL

Another approach could be generation of proxy class from WSDL file by using the WSDL.exe. Once proxy is generated, proxy class could be used for interaction with the Web Service.

SOAP and SOAP XML

Simple Object Access Protocol is a simple XML-based protocol to let applications exchange information over HTTP. SOAP is a protocol for accessing a Web Service.

A SOAP message is an ordinary XML document containing the following elements:

  • An Envelope element that identifies the XML document as a SOAP message
  • A Header element that contains header information
  • A Body element that contains call and response information
  • A Fault element containing errors and status information

The following image displays a sample SOAP Request and Response XML.

Sample SOAP Request Response XML

What’s SOAP Extension – TraceExtension?

SOAP Extensions allow developers to create very interesting applications on top of the core SOAP architecture found within .NET. It allows developers to implement encryption algorithm, compression routine, SOAP attachments, etc. In this article, we will focus on logging the SOAP request/response XML.

For this, we need to create a couple of classes:

  • Create a class that derives from System.Web.Services.Protocols.SoapExtension TraceExtension class has been created for this.
  • Create a class that derives from System.Web.Services.Protocols.SoapExtensionAttribute TraceExtensionAttribute class has been created for this.

A Sample Web Service Application

To understand the functionality of TraceExtension class, I will take a sample WebService and a client which subscribes to that service.

  • HelloWorldWebService – This is a web service with a web method HelloWorld.
    C#
    public class HelloWorldService : System.Web.Services.WebService
    {
            [WebMethod]
            public string HelloWorld(string myString)
            {
                 return "Hello World Service returns - " + myString;
            }
    }
  • ClientSubscriber – This is a simple Windows Form application consuming the web reference of HelloWorldWebService. In the form, there’s a textbox and button. On click of this button, the text of the textbox will send to the web service and the result will displayed in a message box.
  • SoapMessageUtility – This utility has the actual implementation of TraceExtension. The client application has a reference to this utility to log the SOAP request/response XML.

Implementation of TraceExtension

We will implement the TraceExtension in the client side consuming the web service. So the Request/Response SOAP XML logs will be created in the client side.

First we will take look at the TraceExtensionAttribute class inherited from SoapExtensionAttribute. TraceExtensionAttribute must override the ExtensionType property to return the type of extension that is associated with the attribute. In this case, this is nothing but TraceExtension.

C#
public override Type ExtensionType     
{           
    get { return typeof(TraceExtension); }
}

For setting the priority of the ‘SoapExtension’, Priority property has been overridden too.

To have some flexibilities, few properties are created in the TraceExtensionAttribute which can be passed as parameters in the constructor.

  1. LogTypeMode – This denotes which SOAP XML to log – None, RequestOnly, ResponseOnly, RequestReponse
  2. ReqFileName – The file name where Request SOAP XML will be logged
  3. ResFileName – The file name where Response SOAP XML will be logged

TraceExtensionAttribute class can be used at method level as shown below:

C#
[TraceExtensionAttribute(LogType.RequestReponse,
	"C:\\Log\\MyReq.log","C:\\Log\\MyRes.log")]       

[System.Web.Services.Protocols.SoapDocumentMethodAttribute
	("http://tempuri.org/HelloWorld", RequestNamespace=http://tempuri.org/, 
	ResponseNamespace=http://tempuri.org/, 
	Use=System.Web.Services.Description.SoapBindingUse.Literal, 
	ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public string HelloWorld(string myString) {
    object[] results = this.Invoke("HelloWorld", new object[] 
	{                        myString});
    return ((string)(results[0]));
}

Now we will look into the TraceExtension class inherited from SoapExtension. The core piece of implementation is the ProcessMessage method of the SoapExtension class. This method should be overridden to have the proper implementation. Before this implementation, we should be very much aware of the flow of SOAP message from the client to Web Service.

  1. When a web method in the client proxy is called, the framework checks if any SOAP extensions are to be invoked or not and if so, then those are called with BeforeSerialize stage.
  2. Once the serialization is done, then the extensions are called with AfterSerialize stage.
  3. The SOAP message is sent to the server and server figures out which method to route to.
  4. Then the server checks to see if any SOAP extensions (that’s us!) should be invoked, and if so, invokes them with the BeforeDeserialize event stage.
  5. The server deserializes the stream and invokes all the extensions for the AfterDeserialize stage.
  6. After the web method execution server invokes all the extensions with BeforeSerialize stage.
  7. Once the server serializes the result stream, the SOAP extensions are called with AfterSerialize stage.
  8. Result is sent back to client
  9. Now client receives the result stream and framework invokes the SOAP extensions with BeforeDeserialize event stage.
  10. Once client deserializes the result stream, SOAP extensions with AfterDeserialize stage is invoked.

In our case, we will be focused in the client side, i.e. points 1,2,9 and 10.

The key is the AfterSerialize stage (i.e. point 2) in the client, the request SOAP XML can be logged at this moment.

C#
public void WriteOutput(SoapMessage message)
{
    FileStream fs;
    StreamWriter w = null;
    try
    {
        if (_logTypeMode.Equals(LogType.RequestOnly) || 
		_logTypeMode.Equals(LogType.RequestReponse))
        {
            _newStream.Position = 0;
            fs = new FileStream(_reqFilename, FileMode.Append,
                FileAccess.Write);
            w = new StreamWriter(fs); 
            
            string soapString = "SoapRequest";
            w.WriteLine("-----" + soapString + " at " + DateTime.Now);
            w.Flush();
            Copy(_newStream, fs);
            w.Close(); 
        }
    }
    catch (Exception ex)
    {
    }
    finally
    {
        if (w != null)
            w.Close();
        _newStream.Position = 0;
        Copy(_newStream, _oldStream);
    }
}

The same is applicable for the BeforeDeserialize stage (i.e. point 9) to log the response SOAP XML. The WriteInput method logs the response XML.

Safety and Configurability

The whole purpose of this article is to log the request-response SOAP XML. In case of any exception while logging, it would cause interruption in the web service invocation. So the WriteInput and WriteOutput methods in TraceExtension class should take care of proper exception handling. In my case, I kept a blank catch block which can be modified with some exception logging mechanism but that should not impact the normal web service invocation.

Already I tried to provide some flexibilities in the TraceExtensionAttribute with few properties. These can be set while instantiating the attribute in the method level. Also, TraceExtension class can support the following entries in (config files web.config/app.config).

XML
<appSettings>
  <add key ="REQ_LOGFILE" value="c:\log\SOAPReq_log.txt"/>
  <add key ="RES_LOGFILE" value="c:\log\SOAPRes_log.txt"/>

  <add key ="LogTypeMode" value="3"/>
<!-- None = 0,
      RequestOnly = 1,
      ResponseOnly = 2,
      RequestReponse = 3 -->
</appSettings>

If both config entries and attribute parameters are provided, then config entries would override that. So my utility (i.e. SoapMessageUtility.dll) can be directly used with the above configuration entries.

References

I would suggest you all to have a look into the MSDN link on this. Also for beginners to SOAP, the tutorial from w3schools might be helpful.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)