XML-RPC in Actionscript 3.0 – couple of gotchas
As part a recent project, I’ve needed to integrate a Flex 3 application with an existing XML-RPC webservice. Over the years I’ve not done a huge amount of webservice integration with Flash. In the past I would typically choose to send data back and forth from the server using the built in XML or LoadVars objects available in Actionscript 2.0. On a couple of projects, I ended up using the Flash Remoting API and AMFPHP to achieve what I wanted and everything turned out pretty well, and once I integrated an application with some .NET SOAP webservices. But XML-RPC was a new one on me.
Anyway, after a bit of research, I was a little surprised to discover that XML-RPC hasn’t already been supported by the Flex framework, but after looking around I came across as3-rpclib, an open-source library that not only supports XML-RPC, but also AMF0 and JSON-RPC (I’ve currently only used these classes with XML-RPC, so can’t comment on the other formats implements).
So far, the classes have worked really well for me. However I did hit a couple of stumbling blocks along the way which I’ll attempt to detail here.
Information stored in AsyncToken is lost when onResult is sent out
When a service method is invoked using myXMLObject.call (), an instance of AysncToken is returned. A responder can then added to the token, so that when the result is returned from the webservice, the appropriate result or fault hander is called. AsyncToken is a dynamic class, meaning that new properties can be assigned to the instance at runtime without an Exception being thrown. Because of the dynamic nature of the class, it’s fairly common to set a dynamic property of the token which identifies which particular method call was invoked. Something like:
myToken.methodName = "someMethod";
This lets us use one result handler for multiple method calls. Within our result handler we can then examine the token associated with the event, and “switch” based on the methodName property of the token. The code would look something like:
var token:AsyncToken = event.token;
switch (token.methodName) {
case "someMethodName":
doSomething ();
break;
default:
doSomethingElse ();
break;
}
}
I’ve since refactored my code not to use this particular way of handling webservice results, but initially I was using something very similar to the above. However, when I tried this with the as3-xmlrpc library, it didn’t work. token.methodName was always null. After much digging around, I discovered it was a bug in the library code. I’ve raised it as an issue on the Google Code site, but until this issue is patched, here’s a fix. The changes need to be made in the file found at com.ak33m.rpc.xmlrpc.XMLRPCObject, in the onResult method, beginning at line #139.
Existing code:
var token:AsyncToken = evt.target.token;
var resultevent:ResultEvent = ResultEvent(evt.data);
A new ResultEvent is created, which is dispatched later on in the method. However, the token is never set on this new ResultEvent, and so when we examine it in our onResult handler elsewhere, it doesn’t contain the data that we expect. We can fix this by changing the code to:
var token:AsyncToken = evt.target.token;
var currentRE:ResultEvent = ResultEvent (evt.data);
var resultevent:ResultEvent = new ResultEvent (currentRE.type,currentRE.bubbles, currentRE.cancelable, currentRE.result, token);
This will create a new ResultEvent, preserving our token, and our code will now work as expected.
How to send parameters using the ’struct’ datatype
Some of the methods exposed by the webservice I was using required a parameter of type ’struct’. Initially, I couldn’t work out how the hell I could force the Value Objects I was passing to my method calls to be serialised as structs, and as a result any calls I made to the webservice were constantly refused. Eventually I came across the interface com.ak33m.rpc.xmlrpc.IXMLRPCStruct.
package com.ak33m.rpc.xmlrpc
{
public interface IXMLRPCStruct
{
function getPropertyData ():*;
}
}
When I changed my Value Object to implement this Interface, and correctly implemented the getPropertyData method, the calls to my webservice methods began to work.
(Note: I have since discovered that the getting the latest version of the library from SVN renders this particular issue irrelevant. In the SVN version of the code, the XMLRPCSerializer has been updated and will automatically convert Objects to structs. With this change, my webservice calls would have worked from the start. It’s definitely worth checking out the latest version of the code, as there are a couple of other issues which have been fixed too.)
August 7th, 2008 at 1:56 pm
Hi Toby,
Very cool post. I am using PureMVC, as3-rpclib and flex to talk to a Python back end, have you hit any issues with IE 6 & IE 7?
I found that we are getting stream errors occassionally with both those browsers. Especially if requests are done in quick succession.
PS: Its not the cache bug because POSTs don’t use cache and the as3-rpclib uses POSTS for the xmlrpc.
August 7th, 2008 at 3:05 pm
Hi Mark,
I’ve not had problems specific to IE6/7 as far as I know, but I did get a few stream errors when I was firing off too many requests at once. As it happens, Im also using a Python backend. What errors are you getting?
I found it useful to install this tool – http://www.charlesproxy.com/ – to help me figure out what was going on with my service calls when they were failing.
I have found before that IE will stutter if trying to make more than two calls to the same domain simultaneously, which may or may not be the problem I guess.
I started structuring my service calls a little differently in the end so as not to flood the service and haven’t had any problems yet. I’m working on a Mac though, so I’ve not tested it massively in IE 6/7 since making the changes, but might give it a try now to see if I experience the same issues.