I've blogged previously about a Flex application, on which I am currently working, that is backed by .NET Web Services. Other than the Authentication Service, the other Web Services require an authentication Token in order to execute.

Before working on this application, I never worked with Web Services as my data source in Flex (I've typically used Flash Remoting via a ColdFusion server). As such, I am no expert in SOAP requests and responses.

One of the things I had trouble with was getting the data from the SOAP response header's XML. Typically, most the data I need is in the Body of the SOAP response. However, when a user in the application is authenticated, the Token object's details are contained in the SOAP header:





4511ec65-e25b-4c08-8f94-478df913692c
bbd12fa7-f292-4bc5-a37f-06234e877ad8
user_name
e6b3998c-13d9-49fe-a13e-7af27c8229fd




true



As you can see from the code above, the body's response is true (meaning we've been authenticated...naturally, this would be false if authentication failed). However, in order to make another call, I need to extract the Token XML object from the soap:Header element and store it in a Flex object (also called Token).

The problem was that I could not take the E4X approach to XML because the SOAP namespace caused problems (I could not traverse the XML). Here's what I did previously to get around this problem (it works but I know it is 'wrong'):

private function onAuthenticateSuccess( e:ResultEvent ):void
{
var respXML:XML = e.headers[0] as XML;
token = new Token0();
token.Token = new Token();
token.Token.Id = new Guid(respXML.children()[0].toString());
token.Token.UserId = new Guid(respXML.children()[1].toString());
token.Token.UserName = respXML.children()[2].toString();
token.Token.ApplicationId = new Guid(respXML.children()[3].toString());
}

The slightest change in the SOAP Response's Header XML would kill this (i.e., if the element ApplicationId was moved up to the 3rd spot (array index 2) and UserName was moved to the final spot). Plus, it's not only ugly to look at this code but also goes against all the goodness of E4X in AS3.

In one of my iterations, since bagged, I used a Regular Expression to manually remove the namespace from the XML. This sort of worked but when there were multiple namespaces in use, I still ran into problems. So, I stuck with my crappy approach (above).

While working on migrating this application to Flex 4, I started digging into the Flex LiveDocs again today. In so doing, I came across an entry about working with XML data. Specifically, it related to parsing XML data in RSS feed.

While this wasn't directly related to what I was doing, I found a tidbit on namespaces in XML. In short, I learned how to simply reset the XML namespace to a blank namespace (i.e., remove the namespace altogether). As soon as I did this, I was able to use the E4X approach to XML in my ActionScript to cleanly and clearly extract the Token object from the SOAP response's header XML.

Note:
The following code is a little different from the previous block in that it's from Flex Builder 4 (Gumbo), which parsed the Web Services in a different manner than Flex Builder 3 does/did. Specifically, Gumbo produces a cleaner Token object than Flex Builder 3 did. As a result, I did not need to create sub-objects (above is token = new Token0() and then token.Token = new Token()).

private function authResult( evt:ResultEvent ):void
{
var tokenXML:XML = new XML(evt.headers[0]);
if( tokenXML.namespace("") != undefined )
{
default xml namespace = tokenXML.namespace("");
}
token.ApplicationId = tokenXML.ApplicationId;
token.Id = tokenXML.Id;
token.UserId = tokenXML.UserId;
token.UserName = tokenXML.UserName;
}

The key to this solution starts in the second line of the above function (the if statement). I check to see if the XML from the SOAP header has a namespace: if it's not undefined, then we've got a namespace in play. If we find a namespace, the default XML namespace is set to a blank string. Once that's taken care of, it's easy to take the E4X approach, treat my XML (tokenXML) as an object and grab the values from the XML and store in the respective properties of the Token object. This code is SO much cleaner and it has the added benefit of not caring about the order of the XML in the SOAP Header. The server-side developers can make changes and, so long as the properties do not change, my code doesn't care.

I realize this is pretty basic stuff for many who've worked with Web Services in Flex as their data model/source over the years, however, my hope is that it might save someone new to this part of the Flex world a bit of time!

Comments

Anonymous
This comment has been removed by a blog administrator.
Craig Kaminsky
@anon: Thanks for your comment.

In FB3, I did use the WSDL introspection tool, which does indeed create the classes like you describe (I had a problem with the Auth service classes that the WSDL introspection created, which is why I had to go to the XML--there were no classes to get the Token object from the header).

In FB4, it's a bit different. You select an option to "Connect to a Web Service" and then enter the WSDL. However, it does not create these classes any longer. Through the Data/Services view, you are supposed to be able to set the return data type from the service.

In fact the content property of the headers object doesn't exist in FB4! I can see it, however, in FB3. Its interesting where there going with data services in Gumbo and, for the most part, it seems like a major improvement but I'm still trying to figure it all out :)
Anonymous
Craig,

I noticed that you mentioned that Flex Builder parsed yr webservices and was wondering if you meant the WSDL introspection tool in FB3/4.

If so, then you won't be needing to deal with XML at all really. The introspection strong types all the available elements declared in the WSDL of the web service allowing you to treat that Token soap element as the generated Token class. But you have to use the generated Service classes as well in order to be able to take advantage of those benefits. I noticed the typed ResultEvent and assumed you are not, because the response events are also typed to classes and use a naming scheme like AuthenticateResultEvent, where the result property is of course typed. In this case would be a boolean.

If you choose to use the generated services, you can simply access the already typed return token via the headers property of the result event like so:

evt.headers[0].content

If the only returned header is indeed the authenticated token, then can always expect an object of that class, without have to create it yrself.