Thursday, October 23, 2008

Using Flex Webservice component in Flash CS4

One of the most common requests for the Flash team is to provide a Webservice component for Actionscript 3.0 like the one Flash has for Actionscript 2.0. Finally, Flash has provided the features in CS4 to allow users to use any Flex components that does not rely on Flex framework such as Flex WebService component and HTTPService.

In the below example am going to demonstrate how users can use Flex WebService in Flash to get countries names and populate them in a Flash DataGrid component.

1. File > New
2. Select "Flash File (Actionscript 3.0)".
3. Open the Component panel and drag a DataGrid component to the stage and call it "dg".
5. File > Publish settings and click on "Flash" tab.

6. Click on "Settings" button to launch "Advance Actionscript 3.0 Settings"

7. Click on the "library path" tab

8. Click on "Browse to SWC file" icon and get the "framwork.swc" and "rpc.swc" from the Flex SDK as follow :


You can download FlexSDK and select the above SWC's from the following location
"sdks/3.0.0/frameworks/libs/"

9. Open the action panel and import the following:
import mx.rpc.soap.*;
import mx.core.*;
import mx.rpc.events.*;
import fl.data.DataProvider;
10. The following 2 lines of code are required if you are using SDK 3.0.0 but not if you are using higher version of SDK

//The following 2 lines to register class for
//Interface"mx.interface::IResourceManager

var resourceManagerImpl:Object = ApplicationDomain.currentDomain.getDefinition("mx.resources::ResourceManagerImpl");
Singleton.registerClass("mx.resources::IResourceManager", Class(resourceManagerImpl));

11. Now copy the following and paste below the above 2 line of codes


var foo:WebService = new WebService();

foo.addEventListener("load", finishedLoading);

foo.loadWSDL("http://www.webservicex.net/country.asmx?WSDL");

var myOperation:Operation;

function finishedLoading(evt:LoadEvent):void
{
myOperation = Operation(foo.getOperation("GetCountries"));
myOperation.addEventListener("fault", wsdlFault);
myOperation.addEventListener("result", wsdlResult);
myOperation.send();
}


function wsdlFault(evt:FaultEvent):void
{
trace(evt.fault);
}

function wsdlResult(evt:ResultEvent):void
{
trace(evt.result);

var myResult:Object = evt.result;
var len:Number = myResult.length;
var xml:XML = XML(evt.result);
var dp:DataProvider = new DataProvider(xml);
dg.dataProvider = dp;

}

12. Test Movie and you should get a list of all the countries inside the datagrid :

52 comments:

  1. Hi,

    Really good information very helpful "Using Flex Webservice component in Flash CS4"

    thanks

    ReplyDelete
  2. Hi,

    it doesn't work fine for me.
    Looks like the WS is never loaded.
    function finishedLoading(evt:LoadEvent):void is never executed at runtime.
    I used your example with http://www.webservicex.net/country.asmx?WSDL

    What could happen ?

    ReplyDelete
  3. Same here..
    The function finishedLoading seems never to load...

    Ne help??

    ReplyDelete
  4. I just tried it and worked for me. Would you please e-mail me your Fla and i will check it out for you.

    Thanks,
    Tareq

    treguess@gmail.com

    ReplyDelete
  5. I've created the example, nothing else in the file. When I hit "Test Movie," it takes an ungodly amount of time to compile...something like 40 seconds. I have a Dual G5 2.7 GHz PowerMac and am used to pretty speedy compiles. Am I to expect this when using Flex SWCs? Or any SWCs? It has to be those since I don't have anything else really going on in the file. For good measure I removed the DataGrid component but still had really long compiles. Anyone else having this issue?

    ReplyDelete
  6. The performance issue you are seeing is because you are compiling against all the classes in the flex framework "Framework.swc". You won't see this problem with SWC's you create using Flex or Flash.

    ReplyDelete
  7. What is the trick to send parameters to the web service? I checked the Flex docs and it wasn't immediately apparant.

    ReplyDelete
  8. I have a the same question... how can we pass multiple parameters?

    myOperation=Operation(ws.getOperation("GetWeatherByZipCode("+zip+")"));

    ReplyDelete
  9. When I test the movie, I get not a data grid, but a horrific flash of components. The error says "access of undefined property dg."
    The source being the line:

    "dg.dataProvider= dp;"

    Also, the web service used in the example no longer works... I changed the address to another and still got the same Seizure buttons response.

    ReplyDelete
  10. dg is the name of the datagrid instance on stage. You are getting the error because you did not give an instance name to the datagrid. what you need to do is select the datagrid on stage and give it a name as dg inside the Properties Inspector.


    Let me know if you still have a problem and i will send you an FLA.

    ReplyDelete
  11. it works for me...

    but, I little confused, how to edit the data.. it's same with web service in as2 !?

    can u give me an example code to change or edit the data !?

    thanks before... ^^

    ReplyDelete
  12. Tareq,
    This is a very useful post. Coming from flex and trying to learn flash this is one of the most confusing areas for me. however, the flex framework is rather large and bloated, so should i use URLRequest obj instead of importing the framework.swc and using flex's HttpService? Thank you very much.

    ReplyDelete
  13. @Tomas You have to change: http://www.webservicex.net/country.asmx?WSDL

    ... into: http://www.webservicex.com/country.asmx?WSDL

    /Jonas | israelsson.nu

    ReplyDelete
  14. really informative post.
    but can i use the flex httpservice instead of webservice?

    ReplyDelete
  15. Yes, you can use the httpservice in Flash too.

    ReplyDelete
  16. Excellent tutorial!

    "I think I am" and "polarfileio" asked how to pass parameters to a web services. The answer is to add it to the SEND operation as a parameter. E.g. the following query looks up the international dialing code for a country.

    myOperation = Operation(foo.getOperation("GetISD"));
    myOperation.send("France");

    (NB: the web service being used by this tutorial seems to give duplicate answers. So you will get '33' back twice as the response to the above Operation. The above code isn't faulty!)

    ReplyDelete
  17. Hi Tareq,

    Thanks for such a great post about a very frustrating issue. I've got the same problem as @drukepple above with compiles taking ages. In response you said "you won't see this problem with SWC's you create using Flex or Flash."
    I've done some Googling around for how this might be done but I'm still confused. Could you give me any help about how to do this from where you finish your tutorial above?

    ReplyDelete
  18. Thank you, James! Regarding the Web services example, this is the easiest way to use Flex Web service in Flash otherwise you would have to add every single class that being used and needed by the Flex web service component to your Flash source path and I really don't think that would even make it faster. What I meant by "SWC's you create using Flex or Flash" is those SWCs you generate for your custom classes.
    The performance problem that we are seeing here is because Flash is compiling against the whole Flex framework.

    Hope that helps

    tareq

    ReplyDelete
  19. I did all that is asked here, I downloaded the Flex_sdk_3 folder, but the path isn't the same. There is no 3.0.0 folder. I do find the specified swc files n the flex_sdk_3\frameworks\libs folder.

    After failure, I copied and pasted code. Still doesn't work. Puzzlingly, I have no errors.

    The tutorial seems great; I can follow the instructions. Unfortunately, I can't make it work. The trouble is, it is created by one who knows for others who know. It would be nice if one of those who make this would would explain what they did differently (from the instructions) to make it work.

    Just imagine what Adobe would have if they could communicate this stuff!

    Thomas

    ReplyDelete
  20. BTW, I don't mean to pick on you. I appreciate your effort. I realize it isn't your job to teach everyone about Flash. It just seems like there is so little information that is complete. It reminds me of the old books on Chess. It used to be impossible to find a book that could list the moves in the game without horrific mistakes. And I can't find much useful guidance on Flex.

    I'm sure my excuse for a brain plays a part here.

    ReplyDelete
  21. Hey WhidbeyThomas; I'm guessing the problems you're experiencing come from getting the Flex SDK setup. I don't think I've ever downloaded a version of the SDK where it was just named "3.0.0" or whatever, nor is there a "sdks" directory by default on my computer.

    I think an expanded version of what Tareq said in step 8 was...

    Download the Flex SDK

    Unzip it and place it somewhere on your hard drive where you'd like it to live

    Click the target icon and browse to the sdk folder you just unzipped

    From there, go into "frameworks/libs/" and select the "framework" and "rpc" SWCs.

    If it's not just that (sounds like you did get that far), then unfortunately it's really hard to tell without actually looking at your file. "No errors" isn't much to go on. I'd be happy to take a look if you want to email it to me. I'm am on Google's mail service, with a username of drukepple. I hope you can figure out the actual address, and that spam crawlers cannot.

    On another note; you're right that there is a certain level of knowledge assumed. However, as a college instructor I'm acutely aware of the balance one must walk while explaining something to the masses. You will have all sorts of backgrounds and skill levels in the same class, regardless of pre-requisites. I'm not trying to defend either Tareq, or you, as I can see both sides of the argument. On the one hand, you want to provide complete and accessible information. On the other hand, going too far towards "complete" means repeating the same information a lot of the time. Imagine if Tareq had already blogged about the steps necessary to hook up the Flex SDK so Flash CS4 knew where it was. It would be a waste of time to re-write that information just for this post, and it would have been a waste of time for "those who know" to have to read it. At the same time, it would have been nice to link to that article at the appropriate place so that "those who know" could just skip it, while giving the option for "those who don't know" to take a tangental trip so that they become one of "those who know."

    For example. on my blog, I provide tips and techniques as well, a lot of them dealing with JSFL. Rather than repeat the mantra of how to install a JSFL command every time, I created a "how to" page and link to that if necessary. It saves me time, and once you "in the know," it saves you time, too. Assuming you read my blog.

    Anyway, I hope all of this helps.

    ReplyDelete
  22. Hi WhidbeyTomas, Sorry if I was unclear on some of my steps, but I assumed that people who are interested in this subject would already know how to link Flash authoring to the Flex SDK. I guess i was wrong and should pay attention to this kind of stuff in my future blogs. Regarding your issue, just follow what drukepple described in his response and make sure that the Web Service itself works and not down by simply copying the web service link (http://www.webservicex.com/country.asmx?WSDL)and posting it in the browser address bar and then click enter; which should show xml representation of the web service itself if it's working. When i do that now i see "Server is Busy" message which could be why you are not getting any result.
    Let me know if you want me to check out your Fla.
    Thanks,
    Tareq

    ReplyDelete
  23. Thanks to publish nice help blog

    ReplyDelete
  24. Tareq, thanks for this. Amazing how little organiized information there is on something so important.

    To give back, the parameter question was not effectively solved above, because single params default and are easy. But here is a more complex input, output example, inspired by your site tand this guy doing SAP wsdl work:

    http://blog.danmcweeney.com/57

    Say we have wsdl that takes in three parameters, A, B, C with C being an array parameter....
    and returns 2 items D, E

    code looks like this:

    --

    var O:Object = new Object();
    O.A = "a stuff";
    O.B = "b stuff";
    O.C = new Array("C1, C2");
    myOperation.arguments = [O];
    myOperation.send();

    --

    receiving:

    trace(evt.result.D);
    trace(evt.result.E);

    --

    The Dan Sweeney site also talks about in/out parameters.

    Thanks again Man. Good Luck!

    ReplyDelete
  25. Typo above, :

    O.C = new Array("C1", "C2");

    ReplyDelete
  26. I have create a flash movie with flex 3.3. I am trying to access my wsdl file, I am getting the following error

    here1
    [RPC Fault faultString="" faultCode="EncodingError" faultDetail="null"]

    this is my flash code
    import mx.rpc.soap.*;
    import mx.core.*;
    import mx.rpc.events.*;
    import fl.data.DataProvider;

    var foo:WebService = new WebService();

    foo.addEventListener("load", finishedLoading);
    foo.addEventListener("connect",connected);

    //foo.loadWSDL("http://www.webservicex.com/country.asmx?WSDL");
    foo.loadWSDL("http://rubiks.nimbus.info/testWSDL3/newWSDL3.wsdl");

    var myOperation:Operation;

    function finishedLoading(evt:LoadEvent):void
    {

    myOperation = Operation(foo.getOperation("getPlanet"));
    myOperation.addEventListener("fault", wsdlFault);
    myOperation.addEventListener("result", wsdlResult);
    myOperation.send();
    }


    function wsdlFault(evt:FaultEvent):void
    {trace("here1")
    trace(evt.fault);}

    function wsdlResult(evt:ResultEvent):void
    { trace("here2");
    trace(evt.result);

    var myResult:Object = evt.result ;
    var len:Number = myResult.length;
    trace(len);
    var xml:XML = XML(evt.result);
    var dp:DataProvider = new DataProvider(xml);
    dg.dataProvider = dp;
    }

    Please give me some clue as I am new to this Flash programming.

    Note: your example worked perfectly and displayed all the countries.

    ReplyDelete
  27. It seems to me that the issue you are describing is an SDK bug. I am going to confirm and get back to you.

    Thanks,
    Tareq

    ReplyDelete
  28. Could you please send me the following :
    1. wsdl xml file.
    2. soap response xml file.

    thanks,
    tareq

    ReplyDelete
  29. Hi All,
    I just tried my example with Flex SDK 4 and got the following error :

    1046: Type was not found or was not a compile-time constant: [flashx.textLayout.compose]::ITextLineCreator.

    To solve this problem you will need to add
    "textLayout.swc" to the library path in addition to framework.swc and rpc.swc.
    it is located in the following location :

    ..\sdks\4.0.0\frameworks\libs\

    Thanks,
    tareq

    ReplyDelete
  30. Hi,

    I've just emailed my code, I could'nt attach here as html blocks. I managed to connect to the wsdl but could'nt return any value from the function. it always return null.

    Please check the code and let me know.

    Thanks for your time and kind

    ReplyDelete
  31. Try this one~
    (mix article above and p647-650 of Actionscript 3.0 Cookbook)

    //////////////////////////////////////

    import mx.rpc.soap.*;
    import mx.core.*;
    import mx.rpc.events.*;
    import fl.data.DataProvider;

    var myWebService = new WebService();
    myWebService.wsdl = "http://www.webservicex.net/country.asmx?WSDL";
    myWebService.loadWSDL();
    myWebService.addEventListener(LoadEvent.LOAD, loadDone);
    myWebService.addEventListener(FaultEvent.FAULT, loadFault);

    trace('hello?');

    var myOperation:Operation;

    function loadDone(evt:LoadEvent)
    {
    trace("done?");
    myWebService.addEventListener(ResultEvent.RESULT, wsResult);
    myWebService.addEventListener(FaultEvent.FAULT, wsError);
    myWebService.GetCountries();

    // myOperation=Operation(myWebService.getOperation("GetCountries"));
    // myOperation.addEventListener("fault", wsError);
    // myOperation.addEventListener("result", wsResult);
    }

    function loadFault(evt:FaultEvent)
    {
    trace('fault');
    }

    function wsError(evt:FaultEvent)
    {
    trace('something wrong!');
    }

    function wsResult(evt:ResultEvent)
    {
    var xml:XML = new XML(evt.result);
    var dp:DataProvider = new DataProvider(xml);
    MyDG.dataProvider = dp;
    trace('something good!');

    }


    //
    Any question : sseoyh7@snu.ac.kr

    ReplyDelete
  32. Or when you use DocumentClassDefinition with .as file, try this one :

    //////////////////////

    package
    {
    import flash.display.Sprite;
    import mx.rpc.soap.*;
    import mx.core.*;
    import mx.rpc.events.*;
    import fl.data.DataProvider;
    import fl.controls.DataGrid;

    public class WebserviceAndFlashRemotingImplementation extends Sprite
    {
    var _myWebService;

    public function WebserviceAndFlashRemotingImplementation()
    {
    _myWebService = new WebService();

    _myWebService.wsdl = "http://www.webservicex.net/country.asmx?WSDL";
    _myWebService.loadWSDL();
    _myWebService.addEventListener(LoadEvent.LOAD, loadDone);
    _myWebService.addEventListener(FaultEvent.FAULT, loadFault);

    trace('hello?');
    }

    private function loadDone(evt:LoadEvent)
    {
    trace("done?");
    _myWebService.addEventListener(ResultEvent.RESULT, wsResult);
    _myWebService.addEventListener(FaultEvent.FAULT, wsError);
    _myWebService.GetCountries();

    // myOperation=Operation(myWebService.getOperation("GetCountries"));
    // myOperation.addEventListener("fault", wsError);
    // myOperation.addEventListener("result", wsResult);
    }

    private function loadFault(evt:FaultEvent)
    {
    trace('fault');
    }

    private function wsError(evt:FaultEvent)
    {
    trace('something wrong!');
    }

    private function wsResult(evt:ResultEvent)
    {
    var xml:XML = new XML(evt.result);
    var dp:DataProvider = new DataProvider(xml);
    var MyDG:DataGrid = new DataGrid();

    MyDG.width = stage.stageWidth;
    MyDG.height = stage.stageHeight;
    MyDG.dataProvider = dp;
    addChild(MyDG);

    trace('something good!');

    }
    }
    }

    ////
    Any questions : sseoyh7@snu.ac.kr

    ReplyDelete
  33. And this is the same code except for error handling :
    ///////////////

    package
    {
    import flash.display.Sprite;
    import mx.rpc.soap.*;
    import mx.core.*;
    import mx.rpc.events.*;
    import mx.rpc.Fault;
    import fl.data.DataProvider;
    import fl.controls.DataGrid;
    import flash.text.*;

    public class WebserviceAndFlashRemotingImplementation extends Sprite
    {
    var _myWebService;

    public function WebserviceAndFlashRemotingImplementation()
    {
    _myWebService = new WebService();

    _myWebService.wsdl = "http://www.webservicex.net/country.asmx?WSDL";
    _myWebService.loadWSDL();
    _myWebService.addEventListener(LoadEvent.LOAD, loadDone);
    _myWebService.addEventListener(FaultEvent.FAULT, loadFault);

    trace('hello?');
    }

    private function loadDone(evt:LoadEvent)
    {
    trace("done?");
    _myWebService.addEventListener(ResultEvent.RESULT, wsResult);
    _myWebService.addEventListener(FaultEvent.FAULT, wsError);
    _myWebService.GetCountries();

    // myOperation=Operation(myWebService.getOperation("GetCountries"));
    // myOperation.addEventListener("fault", wsError);
    // myOperation.addEventListener("result", wsResult);
    }

    private function loadFault(evt:FaultEvent)
    {
    trace('fault');
    var fault:Fault = evt.fault;
    var message:String = "An error occurred.";// The details are as follows\ncode: " + fault.faultCode;
    message+="\ndetail:"+fault;

    var text:TextField = new TextField();
    text.text = message;
    text.autoSize = TextFieldAutoSize.LEFT;
    addChild(text);

    }

    private function wsError(evt:FaultEvent)
    {
    trace('fault');
    var fault:Fault = evt.fault;
    var message:String = "An error occurred.";// The details are as follows\ncode: " + fault.faultCode;
    message+="\ndetail:"+fault;

    var text:TextField = new TextField();
    text.text = message;
    text.autoSize = TextFieldAutoSize.LEFT;
    addChild(text);
    }

    private function wsResult(evt:ResultEvent)
    {
    var xml:XML = new XML(evt.result);
    var dp:DataProvider = new DataProvider(xml);
    var MyDG:DataGrid = new DataGrid();

    MyDG.width = stage.stageWidth;
    MyDG.height = stage.stageHeight;
    MyDG.dataProvider = dp;
    addChild(MyDG);

    trace('something good!');

    }
    }
    }

    ReplyDelete
  34. great post, but this just makes my swf size BIG "187 KB". Any way to bring it down?

    John

    ReplyDelete
  35. Nice to know this is possible in Flash, but Im having problems getting it to work when I upload it to my server. I get an outline of the datagrid, but nothing else. This all works as it should when im running the swf locally.

    Also, for future reference, will this code work across a secure server?

    Cheers
    Ash

    ReplyDelete
  36. Hi there,
    Does anyone know why this doesn't work when I put it in a class of its own and then call it from my document class?

    ie. I have a class called "WebServiceConnector", that doesn't connect when i import it into the document class, yet works when i set it as the document class.

    any help?
    cheers :-)

    ReplyDelete
  37. There is at least one comment here about how much the file size of your swf will be increased using this Flex SDK approach. In my case, I see a 5K swf increase to something like 342K which is a huge increase and an unacceptable solution for some cases.

    ReplyDelete
  38. I forgot to also add that the sheer compile time of the framework also makes this approach quite a test for you patience since every time you want to test your swf, you're faced with something like a minute of compilation time verses a typical few seconds.

    ReplyDelete
  39. OK, after more research, I have found what appears to be a better alternative to the Flex SDK approach. Please check out:

    http://www.wellconsidered.be/as3-webservice-component/

    I tested this myself and it is working for me. And bonus, no huge swf file sizes or painful compile times. I only tested returning strings from my web service which works fine. Follow the references on the link to see what sort of open issues exist.

    ReplyDelete
  40. the wellconsidered package above does not appear to work out of the box with some wsdl recognition (it appearss very microsoft oriented).

    However, with the source code available in it it does manage to make it pretty apparent on how to write your own just using http POST.

    We have very simple and established wsdl calls, so they have been hard coded into a library and our compile times have been reduced by about 90%. Thanks for the hint.

    I think it shows that the this technoilogy is still a bit immature and still needs to grow from a programming perspective. It seems very hard to get a word on as4? Anyone know?

    ReplyDelete
  41. UPDATE:
    The URL I listed in my post is no longer working:

    (http://www.wellconsidered.be/as3-webservice-component/)

    Instead, please use:

    http://code.google.com/p/as3webservice/

    ReplyDelete
  42. with the as3webservice... is there anything that needs to be done on a hosted platform? any extra ports need to be opened?

    ReplyDelete
  43. Anyone else getting this error?

    "Variable ResourceManagerImpl is not defined"

    ReplyDelete
  44. REGARDING LONG COMPILE TIMES:

    Wanted to update this record that turning off warning messages _vastly_ decreases the compile time in CS4. So those unhappy with the long time should make sure they do this.

    ReplyDelete
  45. @anonymous, regarding turning off warnings:

    But I like warnings. Call me crazy, but I'm not turning them off just so I can use a Flex Webservice component. I doubt I'm the only one who feels that way.

    ReplyDelete
  46. Hey,

    I did the same as you did here, but with HTTPService.

    But I get the following Error:
    "1046: Type was not found or was not a compile-time constant: ResultEvent."

    That is starnge, because I selected the "rpc.swc".

    And I wrote:
    import mx.rpc.http.HTTPService;
    import mx.rpc.FaultEvent;
    import mx.rpc.ResultEvent;

    ReplyDelete
  47. It was a stupid mistake.
    It should be import mx.rpc.events.ResultEvent;

    ReplyDelete
  48. This is working for me when I run it locally, but once I run it on a webserver and browser, there's nothing populating the datagrid anymore. I thought it might be crossdomain.xml, but theirs is wide open. Help?

    ReplyDelete
  49. In Flash you can get this to work with the URLLoader and URLRequest classes too. No need for Flex' HTTPService class.
    For an example check http://www.thetechlabs.com/tutorials/xml/learn-how-to-create-flash-components-using-actionscript-30-xml-and-flickr-api/

    ReplyDelete
  50. Hi Tareq, I need your Help: when I tested the movie in flash cs5,that worked perfectly, but when i Publish the movie, that´s don´t work. What is the problem??

    ReplyDelete
  51. Hi, when i call any of your country.asmx?WSDL methods, like GetCountries, i get an error saying that there is no space on server hdd drive. Is there any option to fix it?

    ReplyDelete