Click here to Skip to main content
Click here to Skip to main content

Trace SOAP Request/Response XML with TraceExtension

By , 17 Aug 2009
 

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.
    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.

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:

[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.

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).

  <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)

About the Author

Arindam Sinha
Software Developer (Senior)
India India
Member
I have been working in IT industry for the last 6 years.
My comfort zone is .NET and Microsoft technologies.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionServer side solutionmemberblavod862 Apr '13 - 21:56 
This is server side solution, not client side!
 
To make this working you need to add the:
[TraceExtensionAttribute(LogType.RequestReponse, "C:\\Log\\MyReq.log","C:\\Log\\MyRes.log")]
attribute to every web service method you want to be logged.
 
The original article describing this method can be found here[^]
 
I am struggling with other problem which maybe one of you have encountered before. This code for one of the web services I want to check gives me empty streams - it looks like the client sends blank request to the web service? How is it possible?
GeneralMy vote of 5memberRai Pawan28 Dec '12 - 0:24 
A wonderful article arindam.
Questionneed step-by-step guide for implement this tracememberTridip Bhattacharjee19 Nov '12 - 3:14 
please tell me what i need to do at client side.
tbhattacharjee

QuestionLogging xml part is not workingmemberTridip Bhattacharjee7 Nov '12 - 1:18 
i run your code from VS2010 IDE. web service work fine but no xml has been logged.
 
where i have to put the below line
[TraceExtensionAttribute(LogType.RequestReponse,
"C:\\Log\\MyReq.log","C:\\Log\\MyRes.log")]
 
i tried to put this in reference.cs but got error. please guide me in detail. thanks
tbhattacharjee

QuestionDownloaded-started_does not workmemberMember 30817928 Oct '12 - 7:00 
Please, test your application first before upload.
Questionserver sidemembersavol9 Apr '12 - 23:59 
many thanks for the good article, the source code doesn't work, though
also how to use the logger on server side?
BugDOESN'T WORKmemberTheCubanP9 Feb '12 - 9:42 
Hello. I downloaded the code, tested it and it didn't work.
The webservice work. Not the capture of the request.
i am using VS2010.
 
thanks
GeneralRe: DOESN'T WORKmemberMember 944119419 Sep '12 - 3:17 
this seems to be missing in de provided project:
[TraceExtensionAttribute(LogType.RequestReponse,
"C:\\Log\\MyReq.log","C:\\Log\\MyRes.log")]
GeneralMy vote of 5memberdivetramp10 Oct '11 - 5:38 
Thanks for sharing this! Very good and to the point information.
Questionvb.net versionmemberacsjimmy20 Jul '11 - 22:29 
I can't get this to work in vb.net version, do you have a sample of this in vb.net version?

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

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130523.1 | Last Updated 17 Aug 2009
Article Copyright 2009 by Arindam Sinha
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid