2007-11-16

Web Services in Flash 9 - AS3: part 2

Re: Carlo Alducente

Thanks for the blessing :) This is my first attempt at publicing code as well as blogging so I'm a bit uncertain about the etiquette, does and don'ts.

Anyway... When trying to create an example of the error handling, I discovered two things:

1. A bug in the call queue. I goofed but now it's corrected.
2. The service allways returned the full response xml. For the moment, I just stripped it so that the content of the Response is returned. The goal is of course to analyse the wsdl and return properly converted data types (strings as strings, ints as ints and complex types as Objects or complex types when the type is registered with a Class alias). This is a project for the future :)

So download the new zip.

...and here is the example:

Service creation:
================================
protected function createService():void {
service = new WebService();
service.addEventListener(LoadEvent.LOAD, onWsdlLoad);
service.addEventListener(FaultEvent.FAULT, onWsdlLoadError);
service.loadWsdl("http://tech.manmachine.se/WebService.asmx?wsdl");
}

protected function onWsdlLoad(event:LoadEvent):void {
trace("wsdl loaded");
}

protected function onWsdlLoadError(event:FaultEvent):void {
trace("wsdl load error: " + event.fault);
}

Service call:
================================
protected function callService():void {
/*
Method 1
Assign IResponder to the AsyncToken
This class implements IResponder
Result is sent to result function and fault is sent to fault function
*/
var token1:AsyncToken = service.Hello("World");
token1.addResponder(this);

/*
Method 2
Listen to events on the AsyncToken
*/
var token2:AsyncToken = service.HelloObject("World");
token2.addEventListener(ResultEvent.RESULT, onResult);
token2.addEventListener(FaultEvent.FAULT, onFault);
}

public function result(data:*):void {
trace("result: " + data);
}

public function fault(info:*):void {
var f:Fault = info as Fault;
trace("fault: " + f);
}

public function onResult(event:ResultEvent):void {
trace("onResult: " + event.result);
}

public function onFault(event:FaultEvent):void {
trace("onFault: " + event.fault);
}

30 comments:

Anonymous said...

Great work! You and Carlo... Question: What exactly does this line of code do:
var token2:AsyncToken = service.HelloObject("World");

How is your web service written? Can you post that here?

Thanks

Anonymous said...

How do you go about parsing the XML result? You have, in your example, "function result(data:*):void{trace("result: " + data);}" and that returns "result: Hello World!". How did you get that individual string ("Hello WOrld")? Is that in relation to how your Web Service was written? I also noticed you have "--target--World--target--
--phrase--Hello World!--/phrase--" How did you get target and phrase in there? (-- = html brackets)

Johan Öbrink said...

Answer 1:

The AsyncToken is the handle for the call. On to the token you can add listeners or listen for events. I demonstrated both methods. token2 is returned by the call for the HelloObject method. This method returns a custom object built with two properties.

Answer 2:
I do not really parse the result. I just return it. What SHOULD be done is that the WSDL parser should pick up the return type definition and cast the result properly. I just haven't had the time to build this yet.

About the web services: They are build with Visual Studio 2005 so everything except the actual methods and the custom Object class is auto generated.

Anonymous said...

Hi, this is great by the way! I am curious how the token thing works. I know you've already been asked about this but could you please explain in more detail how I would go about setting up a web service to use tokens?

Is it just a case of setting up two web services (1st with name of ws, 2nd with name of ws + object) then get the first ws to just return the name of the ws and the second to return the object xml for the 1st ws?

I look forward to your response!

Thanks, Alex

Anonymous said...

Hello Johan, I've downloaded the component you've put here, but i'm new in Actionscript 3.0 and I don't Know where to begin, how to use it, how to prove it. Do you have some step by step tutorial??

Thank you in advance
Marlon mjpena@bancaribe.com.ve

Rodislav said...

it works for me, but sometimes i get this error - "Error opening URL 'http://webservice.com/remoting/public.asmx'
onFault: [Fault (faultCode=ioError, faultString=Error #2032: Stream Error. URL: http://webservice.com/remoting/public.asmx, faultDetail=null)]"

Unknown said...

I fixed a major bug in your class.

In WSProxy you have _busyOnCall = true; within callMethod()

and it gets set to false in onComplete()

but it NEVER GETS SET IN onFault

This frustrated me to no end for days.

Anonymous said...

hi there.. i tried to use your example but it says interface IResponder was not found...

i havent's changed nothing in fla or document class...little help here?

Rodislav said...

probably you had changed the name of folders that contains .as files... if you want i can send you my modification of that webservices, for me they work wery good! thanks to the author! :)

Rodislav said...

#hobbbz

you can describe your fix, or how we can do it.. if it possible..

Unknown said...

To expand on hobbbz findings - the issue surfaces when your web service returns an error (eg you pass it unexpected parameters). Further calls with valid parameters will not work. Thats because _busyOnCall remains true in the event of an exception. Simple fix is to add the following line in WSProxy.as class file

private function onError(event:Event):void {
_busyOnCall = false;
var fault:Fault;
if(event is IOErrorEvent) {
var ioee:IOErrorEvent = event as IOErrorEvent;
fault = new Fault(ioee.type, ioee.text);
} else {
var see:SecurityErrorEvent = event as SecurityErrorEvent;
fault = new Fault(see.type, see.text);
}
var faultEvent:FaultEvent = new FaultEvent(FaultEvent.FAULT, false, true, fault, _token);
_token.dispatchEvent(faultEvent);
}

Anonymous said...

Flash Player Version Alert!

We had used Carlos' original class in a site earlier this year. We started to hear complaints that the service would just sit and spin and never do anything. However we couldn't recreate the issue....until recently.

There were security changes in Flash Player versions sometime around version 9.0.120.0, so versions prior to that (like 9.0.42.0) worked fine, versions after that (like 9.0.124.0) fail.

The solution is to add a new item to the crossdomain.xml file, that looks like this:
{allow-http-request-headers-from domain="[your domain]" headers="SOAPAction"/}

Previously all we had in the crossdomain.xml was this:
{allow-access-from domain="[your domain]" /}

We'll definitely be trying out your extension to this class for error/fault checking, so future changes to Flash can be caught instead of leaving the visitor hanging.

Thanks for the great work!

NOTE: blog wouldn't let me use greater than and less than signs above, so I replaced with curly brackets.

Anonymous said...

I've found that if the web service times out, the proxy object is left in a busy state. Any further calls, simply get queued up and don't get called, so you cannot simply retry the method call. This also occurs even if you recreate the service object and reconnect to the service, because the proxy object is a singleton, and thus still marked as busy. I'm modifying my local version by adding a method to the proxy which allows you to delete the static instance, so that it's recreated next time it's requested. A better solution may exist though...

Anonymous said...

Oh nevermind, I see that hobbbz already addressed this issue with a better solution than what I suggested. (setting _busyOnCall to false within the onError handler)

Harish World said...

Hey guys is it possible to fetch data from this url using your class http://arcweb.esri.com/services/v2/RouteFinder.wsdl > if yes then how Iam unable to do it. but it works fine with AS2 webservice class.....

Anonymous said...

Here is an example of parsing simple SOAP response.

public function result(data:*):void {
// wsdl has finished loading.
trace("wsdl loaded and parsed");

// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

/*
*
* Once this returns VALID XML, should be able to just call
* convertXML(data) and call it a day!
*
* */

// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
var xmlString = XMLList(data);
xmlString.ignoreWhitespace = true;

// convert it to a string
xmlString = xmlString.toXMLString();

// define the regex pattern to remove the namespaces from the string
var xmlnsPattern = new RegExp("xmlns[^\"]*\"[^\"]*\"", "gi");

// remove the namespaces from the string representation of the XML
var namespaceRemovedXML = xmlString.replace(xmlnsPattern, "").replace(/</g, "<").replace(/>/g, ">");

// set the string rep. of the XML back to real XML
var responseXML = new XMLList(namespaceRemovedXML);

//Now you can use e4x on responseXML

}

Unknown said...

hi, this is a great work otherwise its really frustrating to make serialize and unserialize webservice calls on AS3.i m using it right now ad it works fine but i like to ask few things;
1. how can i pass complex objects (e.g. Arrays or objects) as agrs in callService Mehtod? for single args like string & Int type it is working fine but when i pass an array then I wont be able to receive it on the server.
2. Is it possible to receive a complex object in response or the Response must be in XML format?

Plz elaborate it.
thanks haris

Unknown said...

Hello, I was searching the net for a solution for the Webservice problem. And very glad I found this finally :)

In as2 I worked with a Secured Webservice, is this also possible with you class? I worked with SOAP autentication header? How can I work the same way or how can I solve my problem?

Harish World said...

Hey bert can u explaine me abt connecting to secure webservice in AS2 please I was searching for it quite a long was not able to find one.. please help me

smilehari@gmail.com can u send a mail 2 me also if possible

Unknown said...

Thank you for your effort and for publishing this.

Anonymous said...

You just saved me so much time! I would have had to create this on my own and this works superbly!

Anonymous said...

Thanks a lot Johan (and Carlo). This works absolutely great, and it's fairly easy to find your way around in with a bit of as3 knowledge.

Also a cheer for Winton DeShong who made the output data work like a proper XML.

Dudes like you guys make the world turn just a bit faster.

/pete

Unknown said...

Nice work here, but im having problems wiht your code that i didnt had with Carlo Alducente, it connects well to the ws but when i make a request to the ws i get "Error opening URL 'wsURL'
onFault: [Fault (faultCode=ioError, faultString=Error #2032: Stream Error. URL: wsURL , faultDetail=null)]" my requests are like service.GetHighLights(returnFunction, 999);. if you could help out..

Travis Bellamy said...

Hi there, great work with these classes. Just wondering if there was anyway to populate the faultDetail string from the Fault class. It's always null, and doesn't look like it's set anywhere?

Anonymous said...

Hey there, good stuff but for some reason the classes and example are not able for download anymore. Would you mind updating the links?

Thanks!

Exclusive Media News said...

Great read, will save and share.

World Dates said...

cool post, saved.

Osse said...

i really like your post .. i would like to bookmark your site for my future needs :)
dissertations

Buy Logo said...

Resources like the one you mentioned here will be very useful to me! I will post a link to this page on my blog if you don?t mind! Because I am sure my visitors will find that very useful!

Unknown said...

It's a good article. I Have never seen such an article before. You have explained very well about yourself. Thanks for sharing this information.
custom dissertation