Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I capture incoming and outgoing XML from WCF service end

In my solution I have three projects. One is a WCF service, another is a Winforms app from where I am calling the web service, and the last is a class library where class has been design extending soap extension class.

My objective is to capture response & request xml when I am calling the WCF service from my Winforms app. I am getting object reference not set error when I am trying to capture xml.

Here is my class library source code.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.IO;
using System.Net;
using System.Xml;

namespace SoapLogger
{
public class TraceExtension : SoapExtension
{
    private Stream oldStream;
    private Stream newStream;

    private static XmlDocument xmlRequest;
    /// <summary>
    /// Gets the outgoing XML request sent to PayPal
    /// </summary>
    public static XmlDocument XmlRequest
    {
        get { return xmlRequest; }
    }

    private static XmlDocument xmlResponse;
    /// <summary>
    /// Gets the incoming XML response sent from PayPal
    /// </summary>
    public static XmlDocument XmlResponse
    {
        get { return xmlResponse; }
    }

    /// <summary>
    /// Save the Stream representing the SOAP request
    /// or SOAP response into a local memory buffer.
    /// </summary>
    /// <param name="stream">
    /// <returns></returns>
    public override Stream ChainStream(Stream stream)
    {
        oldStream = stream;
        newStream = new MemoryStream();
        return newStream;
    }

    /// <summary>
    /// If the SoapMessageStage is such that the SoapRequest or
    /// SoapResponse is still in the SOAP format to be sent or received,
    /// save it to the xmlRequest or xmlResponse property.
    /// </summary>
    /// <param name="message">
    public override void ProcessMessage(SoapMessage message)
    {
        switch (message.Stage)
        {
            case SoapMessageStage.BeforeSerialize:
                break;
            case SoapMessageStage.AfterSerialize:
                xmlRequest = GetSoapEnvelope(newStream);
                CopyStream(newStream, oldStream);
                break;
            case SoapMessageStage.BeforeDeserialize:
                CopyStream(oldStream, newStream);
                xmlResponse = GetSoapEnvelope(newStream);
                break;
            case SoapMessageStage.AfterDeserialize:
                break;
        }
    }

    /// <summary>
    /// Returns the XML representation of the Soap Envelope in the supplied stream.
    /// Resets the position of stream to zero.
    /// </summary>
    /// <param name="stream">
    /// <returns></returns>
    private XmlDocument GetSoapEnvelope(Stream stream)
    {
        XmlDocument xml = new XmlDocument();
        stream.Position = 0;
        StreamReader reader = new StreamReader(stream);
        xml.LoadXml(reader.ReadToEnd());
        stream.Position = 0;
        return xml;
    }

    /// <summary>
    /// Copies a stream.
    /// </summary>
    /// <param name="from">
    /// <param name="to">
    private void CopyStream(Stream from, Stream to)
    {
        TextReader reader = new StreamReader(from);
        TextWriter writer = new StreamWriter(to);
        writer.WriteLine(reader.ReadToEnd());
        writer.Flush();
    }
    #region NoOp
    /// <summary>
    /// Included only because it must be implemented.
    /// </summary>
    /// <param name="methodInfo">
    /// <param name="attribute">
    /// <returns></returns>
    public override object GetInitializer(LogicalMethodInfo methodInfo,
        SoapExtensionAttribute attribute)
    {
        return null;
    }

    /// <summary>
    /// Included only because it must be implemented.
    /// </summary>
    /// <param name="WebServiceType">
    /// <returns></returns>
    public override object GetInitializer(Type WebServiceType)
    {
        return null;
    }

    /// <summary>
    /// Included only because it must be implemented.
    /// </summary>
    /// <param name="initializer">
    public override void Initialize(object initializer)
    {
    }
    #endregion NoOp
}

Here is how I am calling the web service from my Winforms app:

private void button1_Click(object sender, EventArgs e)
{

    using (ServiceRef.TestServiceSoapClient oService = new ServiceRef.TestServiceSoapClient())
    {
        textBox1.Text = oService.HelloWorld("Sudip");
        var soapRequest = SoapLogger.TraceExtension.XmlRequest.InnerXml;
        var soapResponse = SoapLogger.TraceExtension.XmlResponse.InnerXml;
    }
}

These two lines are causing the object reference error

var soapRequest = SoapLogger.TraceExtension.XmlRequest.InnerXml;
var soapResponse = SoapLogger.TraceExtension.XmlResponse.InnerXml;

I just could not figure out why I am getting error.

The Winforms app has an app.config where I register my class library assembly to capture the xml. Here is my app.config details

<?xml version="1.0"?> 
<configuration> 
<system.serviceModel> 
<bindings> 
<basicHttpBinding> 
<binding name="TestServiceSoap"/> </basicHttpBinding> 
</bindings> <client> <endpoint address="http://localhost:6804/Service1.asmx" 
binding="basicHttpBinding" bindingConfiguration="TestServiceSoap" 
contract="ServiceRef.TestServiceSoap" name="TestServiceSoap"/> 
</client> 
</system.serviceModel> 
<system.web> 
<compilation debug="true" targetFramework="4.0" /> 
<webServices> <soapExtensionTypes> 
<add type="SoapLogger.TraceExtension,SoapLogger" priority="1" group="0" /> 
</soapExtensionTypes> </webServices> 
</system.web> 
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/> 
</startup> </configuration>

When I search google just to know how to capture request/response xml then I got this kind of many article. I followed many but nothing works.

This url I followed to get the job done http://jramirezdev.net/blog/c-tip-capturar-los-mensajes-soap-de-un-servicio-asmx-que-hemos-referenciado

What kind of mistake am I making not clear. I set the break point at every method in my class library method but when web service call no method got executed in the class library. I don't want to use any tool like wireshark, fiddler to capture the request/response xml rather want to do same thing programatically.

So please guide me what is my mistake? Why am I getting object reference not set error? Please have a look at my code or go to the url link and tell me what is wrong in my approach

like image 547
Thomas Avatar asked Nov 30 '22 19:11

Thomas


2 Answers

Simply we can trace the request message as.

OperationContext context = OperationContext.Current;

if (context != null && context.RequestContext != null)

{

Message msg = context.RequestContext.RequestMessage;

string reqXML = msg.ToString();

}
like image 77
Shebin Avatar answered Dec 03 '22 07:12

Shebin


  1. Configure WCF Tracing
  2. Send/receive some messages
  3. Get the SvcTraceViewer.exe log viewer and open the trace output.
  4. Profit.
like image 27
tom redfern Avatar answered Dec 03 '22 07:12

tom redfern