Trace SOAP Request/Response XML with TraceExtension - SoapExtension - C#
Sometimes we need to send a sample of our request SOAP / XML web service response. I leave you a practical example without much return, I hope will be helpful
Class TraceExtension
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Web.Services.Protocols; using System.IO; using System.Xml; namespace TestProject { 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 } }
Method soapMessageRecord
private void soapMessageRecord(string nombreMetodo) { StreamWriter escritorReq = File.CreateText("C:\\logs\\request_" + nombreMetodo+ "_" + DateTime.Now.Ticks + ".xml"); StreamWriter escritorRes = File.CreateText("C:\\logs\\response_" + nombreMetodo+ "_" + DateTime.Now.Ticks + ".xml"); // Object is accessed "XMLRequest" TraceExtension class and call property "OuterXml". string soapRequest = TraceExtension.XmlRequest.OuterXml; string soapResponse = TraceExtension.XmlResponse.OuterXml; escritorReq.Write(soapRequest); escritorReq.Close(); //Access to the object "XmlResponse" TraceExtension class and called his property "OuterXml". escritorRes.Write(soapResponse); escritorRes.Close(); }
Mode of use; Example
private void getStudentData(int identification)
{
PJWS.proxy2013 ws = new PJWS.proxy2013();
PJWS.getStudentDataResponse data = new PJWS.getStudentDataResponse();
data = ws.getData(identification);
//call the above method most suitable
soapMessageRecord("getStudentData");
// or simply gain access in this way.
var soapRequest = TraceExtension.XmlRequest.OuterXml;
// or simply gain access in this way
var soapResponse = TraceExtension.XmlResponse.OuterXml;
}
In the web.config must add the following lines:
<system.web> <compilation debug="true" targetFramework="4.0" /> <webServices> <soapExtensionTypes> <add type="TestProject.TraceExtension, TestProject" priority="1" group="0" /> </soapExtensionTypes> </webServices> </system.web>
See Also:
Thank you a lot of.
ReplyDeleteDoesn't work for me where you put:
ReplyDeletevar soapRequest = TraceExtension.XmlRequest.OuterXml;
"XmlRequest" is null. I can't recover the soap message.
The only way it works for me is writing in a file, but I need another solution. I can't use files in my app.
Have you made sure that the request is not null?
DeleteThis method works when you go to consume WS from a client.
Could you send me your code snippet, admin@systemdeveloper.info
DeleteAngelo, so you just copy and paste this crappy code from another punk like you. Nice! Way to go.
DeleteThanks for answer! Fortunelly I made it work jeje. I forget to register the soapextension class in web.config file. But I had to modify the TraceExtension class because the request where mixed. That is, the request A mingled with the response B.
ReplyDeleteGreat, it would be interesting if you could share your modified code .. xD
DeleteSure! Here it is:
DeleteFirst I added a new field:
private int session;
Second, modified the Initialize method:
public override void Initialize(object initializer)
{
if (session == 0)
session = System.Threading.Thread.CurrentThread.GetHashCode();
}
Finally, modified the AfterSerialize and BeforeDeserialize stages:
case SoapMessageStage.AfterSerialize:
if (session == System.Threading.Thread.CurrentThread.GetHashCode())
{
xmlRequest = GetSoapEnvelope(newStream);
CopyStream(newStream, oldStream);
}
break;
case SoapMessageStage.BeforeDeserialize:
if (session == System.Threading.Thread.CurrentThread.GetHashCode())
{
CopyStream(oldStream, newStream);
xmlResponse = GetSoapEnvelope(newStream);
session = 0; //restart session variable
}
break;
Comparing the hash of the current thread I could avoid to mix several request and responses. Thanks again for iluminate me!
Glad you has been useful!!!
DeleteSorry i'm a beginner.
DeleteI create form application as a web service client.
where i use this code ???
in my client or in web service?
Hi Angelo. I have the same problem as (AnonymousApril 2, 2014 at 3:18 AM).
ReplyDelete"XmlRequest" is null.
I call "soapMessageRecord" exactly after invoking web service method, but for some reason XmlReques comes as null
Also I tried to use TraceExtension as DLL building it in another project, as well as using it as class within the project where I call web service. In both cases XMLRequest is null
This comment has been removed by a blog administrator.
ReplyDeleteThis comment has been removed by a blog administrator.
ReplyDeleteThis comment has been removed by a blog administrator.
ReplyDeleteThis comment has been removed by the author.
ReplyDeletegetStudentData is a webmethod or what , pls explain
ReplyDeleteIt was my mistake, now it is already fixed. Thanks
Deletein my case i am not able to add soapExtensionTypes to web.config. it giving metadata error .
ReplyDeleteThis comment has been removed by the author.
ReplyDeleteThis comment has been removed by the author.
ReplyDelete" Failed to add a service. Service metadata may not be accessible. Make sure your service is running and exposing metadata. " error after adding soapExtensionTypes to web.config
ReplyDelete