XML Replay: Difference between revisions
mNo edit summary |
m added cookbook category |
||
(7 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
When attempting to diagnose problems which occur within web service environments, it is often useful to be able to re-run the XML which triggered the problem, so as to be able to step through it in the Visual DataFlex Studio debugger. The XML passed to a web service can be logged (see [[XML | When attempting to diagnose problems which occur within web service environments, it is often useful to be able to re-run the XML which triggered the problem, so as to be able to step through it in the Visual DataFlex Studio debugger. The XML passed to a web service can be logged (see [[XML Logging]] for details of how this can be done) and this historic data can then be used to "''replay''" the offending call and see what probably happened. | ||
Assuming you have access to the original XML (see [[XML | Assuming you have access to the original XML (see [[XML Logging]]), this can then be saved into a text file - usually with the extension ".xml". This XML is then ready for incorporation into a SOAP message for re-sending to your service, running under a debugger, so you can set breakpoints and trace the execution through, step by step. | ||
In order to do this however, you are going to need a client which operates at a lower level than the standard web service client class you are able to generate for your service using the Studio's Web Service Client Class Generator. The following is an example of how you might do this using an object of the cXmlHttpTransfer class. | In order to do this however, you are going to need a client which operates at a lower level than the standard web service client class you are able to generate for your service using the Studio's Web Service Client Class Generator. The following is an example of how you might do this using an object of the cXmlHttpTransfer class. | ||
Line 27: | Line 7: | ||
Use cXmlHttpTransfer.pkg<br /> | Use cXmlHttpTransfer.pkg<br /> | ||
Object oTfr is a cXmlHttpTransfer | Object oTfr is a cXmlHttpTransfer | ||
End_Object // oTfr | End_Object <span style="color:green;">// oTfr</span> | ||
Procedure InvokeService | Procedure InvokeService | ||
Line 33: | Line 13: | ||
Boolean bOK | Boolean bOK | ||
String sServer sURI<br /> | String sServer sURI<br /> | ||
< | <span style="color:green;">// Create the XML document and load your XML:</span> | ||
Get Create U_cXmlDomDocument to hoDoc | Get Create U_cXmlDomDocument to hoDoc | ||
Set psDocumentName of hoDoc to (Value(oInput(Self))) | Set psDocumentName of hoDoc to (Value(oInput(Self))) | ||
Line 42: | Line 22: | ||
End<br /> | End<br /> | ||
Get DocumentElement of hoDoc to hoMsg<br /> | Get DocumentElement of hoDoc to hoMsg<br /> | ||
< | <span style="color:green;">// Create the SOAP message, adding the initial processing instruction, | ||
// the "Envelope" document element, the "Body", then append your XML to that:</ | // the "Envelope" document element, the "Body", then append your XML to that:</span> | ||
Get Create U_cXmlDomDocument to hoXML | Get Create U_cXmlDomDocument to hoXML | ||
Send AddChildProcessingInstruction of hoXML "xml" 'version="1.0"' | Send AddChildProcessingInstruction of hoXML "xml" 'version="1.0"' | ||
Line 49: | Line 29: | ||
Get AddElement of hoEnv "soap:Body" "" to hoBody | Get AddElement of hoEnv "soap:Body" "" to hoBody | ||
Get AppendNode of hoBody hoMsg to hoMsg<br /> | Get AppendNode of hoBody hoMsg to hoMsg<br /> | ||
< | <span style="color:green;">// Set up the HTTP headers:</span> | ||
Send ClearHeaders of oTfr | Send ClearHeaders of oTfr | ||
Set psAcceptTypes of oTfr to "text/*" | Set psAcceptTypes of oTfr to "text/*" | ||
Set psContentTypeSent of oTfr to "text/xml; charset=UTF-8" | Set psContentTypeSent of oTfr to "text/xml; charset=UTF-8" | ||
Get AddHeader of oTfr "SOAPAction" ('"' + Value(oOperation(Self)) + '"') to bOk<br /> | Get AddHeader of oTfr "SOAPAction" ('"' + Value(oOperation(Self)) + '"') to bOk<br /> | ||
< | <span style="color:green;">// Prepare the transfer object for sending:</span> | ||
Get Value of oServer to sServer | Get Value of oServer to sServer | ||
Get Value of oURI to sURI | Get Value of oURI to sURI | ||
Set piRemotePort of oTfr to (Value(oPort(Self)))<br /> | Set piRemotePort of oTfr to (Value(oPort(Self)))<br /> | ||
< | <span style="color:green;">// Send the message:</span> | ||
Get HttpPostXmlNode of oTfr sServer sURI hoXML to hoXMLResponse<br /> | Get HttpPostXmlNode of oTfr sServer sURI hoXML to hoXMLResponse<br /> | ||
< | <span style="color:green;">// Deal with the response:</span> | ||
If (hoXmlResponse=0) Set Value of oReturnedXML to "NO RESPONSE" | If (hoXmlResponse=0) Set Value of oReturnedXML to "NO RESPONSE" | ||
Else Set Value of oReturnedXML to (psXml(hoXmlResponse))<br /> | Else Set Value of oReturnedXML to (psXml(hoXmlResponse))<br /> | ||
< | <span style="color:green;">// Tidy up:</span> | ||
Send Destroy of hoXML | Send Destroy of hoXML | ||
If hoXMLResponse Send Destroy of hoXMLResponse<br /> | If hoXMLResponse Send Destroy of hoXMLResponse<br /> | ||
End_Procedure // InvokeService | End_Procedure <span style="color:green;">// InvokeService</span> | ||
The above code obviously assumes the existence of objects (probably mostly of the class "Form") which contain the relevant information for the operation invocation: | The above code obviously assumes the existence of objects (probably mostly of the class "Form") which contain the relevant information for the operation invocation: | ||
Line 75: | Line 55: | ||
*oURI - the URI of the service within the host: e.g. "MyService/TestService.wso" | *oURI - the URI of the service within the host: e.g. "MyService/TestService.wso" | ||
*oReturnedXML - an object of class "cTextEdit" to take and display the response XML | *oReturnedXML - an object of class "cTextEdit" to take and display the response XML | ||
[[Category:Web Services]] [[Category:Cookbook]] |
Latest revision as of 16:27, 22 November 2007
When attempting to diagnose problems which occur within web service environments, it is often useful to be able to re-run the XML which triggered the problem, so as to be able to step through it in the Visual DataFlex Studio debugger. The XML passed to a web service can be logged (see XML Logging for details of how this can be done) and this historic data can then be used to "replay" the offending call and see what probably happened.
Assuming you have access to the original XML (see XML Logging), this can then be saved into a text file - usually with the extension ".xml". This XML is then ready for incorporation into a SOAP message for re-sending to your service, running under a debugger, so you can set breakpoints and trace the execution through, step by step.
In order to do this however, you are going to need a client which operates at a lower level than the standard web service client class you are able to generate for your service using the Studio's Web Service Client Class Generator. The following is an example of how you might do this using an object of the cXmlHttpTransfer class.
Use cXmlHttpTransfer.pkg
Object oTfr is a cXmlHttpTransfer End_Object // oTfr Procedure InvokeService Handle hoXML hoXmlResponse hoEnv hoBody hoDoc hoMsg Boolean bOK String sServer sURI
// Create the XML document and load your XML: Get Create U_cXmlDomDocument to hoDoc Set psDocumentName of hoDoc to (Value(oInput(Self))) Get LoadXmlDocument of hoDoc to bOK
If not bOK Begin Error 0 ("Could not load document" * psDocumentName(hoDoc)) Procedure_Return End
Get DocumentElement of hoDoc to hoMsg
// Create the SOAP message, adding the initial processing instruction, // the "Envelope" document element, the "Body", then append your XML to that: Get Create U_cXmlDomDocument to hoXML Send AddChildProcessingInstruction of hoXML "xml" 'version="1.0"' Get CreateDocumentElementNS of hoXML "http://schemas.xmlsoap.org/soap/envelope/" "soap:Envelope" to hoEnv Get AddElement of hoEnv "soap:Body" "" to hoBody Get AppendNode of hoBody hoMsg to hoMsg
// Set up the HTTP headers: Send ClearHeaders of oTfr Set psAcceptTypes of oTfr to "text/*" Set psContentTypeSent of oTfr to "text/xml; charset=UTF-8" Get AddHeader of oTfr "SOAPAction" ('"' + Value(oOperation(Self)) + '"') to bOk
// Prepare the transfer object for sending: Get Value of oServer to sServer Get Value of oURI to sURI Set piRemotePort of oTfr to (Value(oPort(Self)))
// Send the message: Get HttpPostXmlNode of oTfr sServer sURI hoXML to hoXMLResponse
// Deal with the response: If (hoXmlResponse=0) Set Value of oReturnedXML to "NO RESPONSE" Else Set Value of oReturnedXML to (psXml(hoXmlResponse))
// Tidy up: Send Destroy of hoXML If hoXMLResponse Send Destroy of hoXMLResponse
End_Procedure // InvokeService
The above code obviously assumes the existence of objects (probably mostly of the class "Form") which contain the relevant information for the operation invocation:
- oInput - the path/name of the XML file to load and send
- oOperation - the operation (function) name beng invoked
- oServer - the server or IP address the service is running on (localhost in most debugging scenarios)
- oPort - the port number to use (80 by default)
- oURI - the URI of the service within the host: e.g. "MyService/TestService.wso"
- oReturnedXML - an object of class "cTextEdit" to take and display the response XML