Sunday, April 25, 2010

XML Parsing and SOAP messages

For a recent project, I needed to create a Web Services Conversation Language (WSCL) document (actually, four of these) and then be able to use another Web Service acting as a conversation handler to parse this XML and verify the protocols contained in the WSCL doc. This proved to be a challenge and reminded me that I need to better learn XML parsing in Web Services.

When a Web Service is created in Visual Studio, the service can be launched in a browser window. This page will show you the service available as well as a link to the WSDL document, and comments on the namespace if it is set to the default URL of tempuri.org. The screenshot below shows an example of this page.


Clicking on a Service name will allow you test the functionality of the service. Here is where an important note is annotated. When testing the operation directly, the parameters used are sent using HTTP POST. However, when accessing the Web Service through another application/service, the parameters are passed using SOAP messages by default.


So why is this important you might ask? Something gets lost in translation with the differences between HTTP POST and SOAP messages. When attempting read an attribute from an XML element, one can use the XMLReader.GetAttribute() function. This function is overloaded to allow for example: an int parameter (the index value of the attribute) or a string value of the attribute's XName. So, when parsing an XML document, one way to do this (using Visual Studio 2008, C#) is with something similar to the following:

using (XmlReader reader = XmlReader.Create(url))
{
reader.Read();
reader.ReadToFollowing("DestinationInteraction");
reader.MoveToFirstAttribute();
StartOp = reader.GetAttribute("href");
reader.Close();
}

This block of code will create an XML reader object (reader) and will then move to first Element with a name value of "DestinationInteraction." The reader is then moved to the first attribute of the Element and then assigns to (string)StartOp the value of the "href" attribute. An example of the portion of the WSCL document that this is reading is:

Notice that this Element has no values, only an attribute of "href" that has the value "OPName." And this is where the fun begins.

Parsing the value of Elements in an XML document is generally very easy. A developer can code such that only the required Element(s) is accessed (reducing overhead), or can parse the entire document, storing needed values for the application. It's the parsing of attributes, specifically using an "int" as the parameter that presents a problem.

The bottom line is this:
When using HTTP POST the XMLReader.GetAttribute(int i) will work properly. However, when attempting to use the int parameter in a SOAP message, this failed for me every time, with either an out-of-bounds error message (attributes can be accessed like an array [0...n]) or an invalid parameter error message. Needless to say that this was very frustrating for me, especially since I spent a LOT of time on this only to realize that the easy answer was to use the string parameter.

Using XMLReader.GetAttribute(string s) function allows the operation to execute properly (as long as s is a valid XName of the attribute) in both HTTP POST actions and with SOAP messages.

Unfortunately, this was another thing on which I spent a LOT of time that I really didn't have. I was not able to determine the cause of the problem, although it is obviously something in the way the SOAP messages are being handled. I assume it's the way that the client side is parsing the SOAP message and believe that although the SOAP message passes the int parameter as an int, the client-side is most likely parsing the int and casting it to a string. I have finals this week and will be focused on that in my free time. However, as SOON as my finals are over, I plan to spend some time on this one as I really want to know what the failure mechanism was with this operation.