| Register
Saturday, May 17, 2008   

Speed Boost: Simplified Flash Remoting Code

Created By  Jed Wood, at  11/16/2004 - 25 comments.

Click to view this author's website.

Those with Adult ADD or otherwise not in the mood for reading, grab the zip files here and knock yourself out.


I have determined that Flash Remoting is like so many other technologies (i.e CSS, RSS, Lou Malnati's pizza): you hear about them, think to yourself  "yeah, I'll get around to that sometime," and when you finally do, you can't imagine doing things any other way.


Right now I'm co-teaching an Interactive Media class at the Institute of Design. When faced with the task of helping 25 students (many with little or no Actionscript experience, let alone PHP/MySQL) create data-driven Flash applications, I knew I needed to provide some kind of template files that would not only help everyone get started, but also allow us to deal with one common set of server-connection issues. I had 5 requirements:


  • Reduce all the basic Flash Remoting setup to one line of Actionscript.

  • Cache results on the client side

  • Add new methods on the server side without updating the Actionscript classes

  • Provide a flexible, somewhat encapsulated broadcaster/listener event model

  • Require no other downloads or component installations beyond these template files.

I'm happy to say that with help of Flash All-Stars Joey Lott and Grant Skinner, I pulled it off. Read on for more details.

One method, 2 arguments (3rd optional)


Flash Remoting provides several different ways to set up your connection and responder objects. Options are nice, but when you're getting started (or even after you've done several projects) most of us just want to copy and paste the tutorial sample and get working with our live data. So here's what the constructor looks like for our class:


var remote:RemoteHandler = new RemoteHandler("FlashZen", "http://www.flashzengarden.com/gateway.php", true);

The first argument is the name of the remote service, then the path to the gateway file, and finally an optional true/false of whether you want a bunch of trace statements for debugging purposes (the default is false).


Here's how you actually make a remote call:


remote.serve("myMethodName", cacheTimeInMinutes, arg1, arg2, ..., argN);

The first argument is of course the name of the remote method. The second argument is the how long any cached data is considered "fresh." Put 0 (zero) in there and it'll always pull straight from the server.


All we need now is a listener


(or two or three if you want). We can set one up like standard AS2 listeners, like this:


var myListener:Object = new Object();
remote.addEventListener("ALL", myListener); //Using GDispatcher

myListener.onMyMethodName = function(obj) {
	trace ("

 Successful return of results" + obj.result);
}

And that's it. For more details, read the rest of the article, take a look at the sample file, and drop any questions here in the comments.


Better than cookies


You probably know about Flash Shared Objects. If you don't, check out a tutorial. Basically, they give us a way to store Actionscript Objects on the user's machine, tucked away in some directories somewhere that most users don't even know about. They're especially cool because:



  • They work across all the browsers on that machine. Visit a site in Mozilla, see your saved data show up in IE.

  • They don't get erased when the users deletes the browser cookies.

  • You can store Actionscript objects, arrays, and even classes with methods, not just measly little strings and numbers.


Many times the data being pulled from the server doesn't change that often. By utilizing these Shared Objects to store the results, we can give the users almost instant results, and save a little bandwidth in the process. This was probably the trickiest part of the code for me to write, but all you need to know is that if a method is called with the same arguments within the cache lifetime, no server call is made. Instead, instant results are pulled from the cache and broadcast as if they came from the server.


Room to grow


The classes for this API needed to be structured in a "dynamic" way that would allow any method to be called, and the response returned to the appropriate object. Using a little help from array access [  ] , Function.apply(), and the GDispatcher (distributed with permission, thanks Grant), it worked out. Of course the listeners you create will need to be updated when new server-side methods are added, but nothing in the "middle" needs to change.

Encapsulation. really.


I don't know about the rest of you, but encapsulation is one of those things I always want to acheive, yet so often I end up mucking it up with some hard coded "_global" or otherwise external values, especially when things start getting complex. This time I think I did okay. The RemoteResponder is going to broadcast a message when it receives the response from the server (or cache) and any and all listeners can respond. Listeners just need to have a method that matches the name of the remote method plus "on" tacked-on to the front. For example, if my remote call is "getName", then my listener would need a "onGetName" method (notice the change in capitalizing the first letter of the method name). Errors can be picked up by adding "Error" on the end, like "onGetNameError." The object broadcast in both cases is an event object (not just the return value), which means you'll need to access

obj.result
to get at the actual value that is returned from the server. So if my return value is an object with name and age properties, I would access the age property using
obj.result.age
.

One-stop shop


Thanks to Joey, I'm able to package up AS2 Flash Remoting files along with everything else, which means you don't even need to download or install them seperately. But wait- there's more! I've even used a combination of Grant's preloader (with my own flavor added) and Colin Moock's template setup for the .FLA structure. Now whenever I (or my students) start a new data-driven Flash app, I open up this template file, and a sizeable chunk of work is already done. Though I can't eliminate the server-side issues you have to deal with for your own Remoting (or LoadVars for that matter) setup, perhaps these classes and sample files will help you start Remoting until you get around one of the good (but thick) books on the subject and learn all the ins and outs. Even if you don't have any problems setting up Remoting, or if you just use LoadVars, maybe the extensive caching via Shared Objects will be of interest.


As always , if you have any bug reports, suggestions, or questions: the comments await you...

Need Professional Help For Your ActionScript Project?
ActionScript.com Consulting Services provide top quality professional ActionScript consulting to businesses around the globe. If you have a professional project in need to world-class talent, tell us about your project by requesting a quote today.

Reader Comments

  1. aran  Replied:
    ( 2/11/2005 At 9:16 AM)

    Hi Jed.
    Good work on the caching etc.
    In regards to the AS2 remoting classes that you packaged - Are they the same as macromedia's ? (http://download.macromedia.com/pub/flashremoting/mx2004/components/actionscript_2.0/flashremoting_comp_sourcecode.zip)
    Or are they Joey Lott's original AS2 classes?
    I just want to make sure that I am not losing any functionality ( I am used to having) by using the packaged classes etc.
    Cheers,
    Aran

  2. Jonathan Langdale  Replied:
    ( 2/13/2005 At 9:14 AM)

    I'm getting errors in the com.usableflash.remoting.RemoteResponder
    RemoteResponder.as checks out with errors in MX 2004.
    **Error** G5150HD:Users:jonl:Desktop:Downloads:UFRemotingCache:source:com:usableflash:remoting:RemoteHandler.as: Line 75: There is no method with the name 'UFTracer'.
    UFTracer.traceObject(result);

  3. aran rhee  Replied:
    ( 2/15/2005 At 4:57 AM)

    Jonathan.
    Looks like you are missing the tracer class (or it is not in the right place)
    it is originally found at:
    (source) com.usableflash.utils.UFTracer.as
    You'll notice it is imported (in the 7th line) of remoteHandler.as
    if you don't need error checking / debug info ( this is all the class is used for), then set your 3rd param to false when instanciating a new remoteHandler.

  4. Jed Wood  Replied:
    ( 2/19/2005 At 3:55 AM)

    Aran-
    Yes, these are Joey's AS2 remoting classes, distributed with his permission.
    Jonathon-
    Let me know if you have any further problems getting things to compile.

  5. michael  Replied:
    ( 2/28/2005 At 10:18 PM)

    Hi,
    I have difficulties handling pageable recordSet requests with UFRemotingCache.
    Events are dispatched but there is no returns.
    See for the current csv example:
    http://cvs.sourceforge.net/viewcvs.py/amfphp/sources/examples/pageableRecordSet/
    http://www.amfphp.org/wiki/doku.php?id=using_pageable_resultsets
    Regards,
    Michael.

  6. Brian Grayless  Replied:
    ( 3/12/2005 At 1:45 AM)

    Using these classes, how can I do the equivalent of the:
    NetDebug.trace("foo");

  7. Aran rhee  Replied:
    ( 3/14/2005 At 8:07 AM)

    (in some class)
    import com.usableflash.utils.UFTracer;
    UFTracer.traceObject(AnObj.data);
    (will loop through movieclip / object properties and indent / display as necessary)

  8. Brian Grayless  Replied:
    ( 3/14/2005 At 9:26 PM)

    The UFTracer.tracObject() simply uses a normal trace, correct?
    I need the ability to trace to the NetConnection Debugger window, like I would with NetDebug.trace()...
    That's where the problem is. My application structure needs don't allow me to run the app in the Flash IDE, so I have to trace everything to the NetConnection Debugger if I want to see anything.
    Any ideas? I've tried including the usual classes that would allow me to do that, but no luck yet.

  9. Jed Wood  Replied:
    ( 3/14/2005 At 9:35 PM)

    Brian-
    Right, just the regular trace. If anyone has suggestions on another method, I'm happy to try and include it.
    -Jed

  10. Brian Grayless  Replied:
    ( 3/15/2005 At 1:18 AM)

    Jed, thanks for the quick response. I don't know if most Flash Remoters are familiar with the NetConnection Debugger or not. It's the window built in the IDE, that when running, traps and displays every possible detail about each remoting request, whether you're running it in the IDE or not. It's crucial if you want to monitor your program without depending on anything in the IDE. It can be opened by going to Window->Other Panels->NetConnection Debugger.
    The last project I used remoting on was before the remoting tools caught up with AS 2.0, so things were a little different, but we were able to include the necessary remoting libraries and call:
    NetDebug.trace("foo");
    anywhere in our code and it would trace the info to the NetConnection Debug window along with all the other remoting details.
    From what I can tell, your classes have extended the native Flash classes and include them in your class structure, however, in trying various ways to extend, initialize or import the proper object, I can't seem to get anything to output to the NetConnection Debugger. I did see some comments in the included NetDebug.as, that seem to affect it's internal "trace" function, but I don't want to jack with working code.
    Any assistance on figuring this out would be enormously valuable. I love what the UF classes do, however, output to the remoting debugger is quantum for a complex application.
    Brian

  11. Aran Rhee  Replied:
    ( 3/15/2005 At 5:53 AM)

    Ok, sorry I didn't understand your requirements from your post Brian. I use the netdebug window daily, and appreciate it is necessary on any remoting project.
    You can get the netDebug to output anythting like this:
    myObj = [];
    myObj.push({foo:"bar0", bar:"foo0"});
    myObj.push({foo:"bar1", bar:"foo1"});
    myObj.push({foo:"bar2", bar:"foo2"});
    myObj.push({foo:"bar3", bar:"foo3"});
    // a string trace
    NetDebug.trace("hello");
    // an associative array trace
    NetDebug.trace(myObj);
    // a bit more granular (add you own debug levels etc.
    NetDebug.trace({level:"Debug", message:"something"});
    // I suppose you could do a for loop in your results too if you wanted
    for(var a in rs.result) NetDebug.trace([a, rs.result[a]])
    If you saved your remoting call results as variables, you could look at the results in a remote debugging window as well (rather than netdebug). (allow remote degugging option in the debug window) You still need the IDE though...
    For this type of thing you can check out the standalone admintool (if you don't have/want access to the flash IDE):
    http://acmewebworks.typepad.com/admintool/2005/01/the_admintool_w.html
    Back to tracing in netDebug, you should just be able to:
    (in whatever class you are using)
    //import debug class (comes with MM official AS2 remoting classes)
    import mx.remoting.debug.NetDebug;
    // start the debugger
    NetDebug.initialize ();
    //
    // then replace whatever trace calls you want with NetDebug.trace
    Does any of this help?
    Aran

  12. Brian Grayless  Replied:
    ( 3/15/2005 At 11:41 PM)

    Aran,
    That was helpful, but I'm still having problems.... Here is the exact code that I'm using. I'm not including any components, or anything. This is the only stuff in the .fla file.
    *******
    import com.usableflash.remoting.RemoteHandler
    import mx.remoting.debug.NetDebug
    NetDebug.initialize ();
    var remote:RemoteHandler = new RemoteHandler("Kadmin", "http://kae-admin.brian.local/gateway.php", true);
    var myListener:Object = new Object();
    remote.addEventListener("ALL", myListener);
    var myOtherListener:Object = new Object();
    remote.addEventListener("ALL", myOtherListener);
    myListener.onGetGoogFeed = function(obj) {
    trace ("\\ Successful return of results");
    }
    myOtherListener.onGetGoogFeed = function(obj) {
    trace ("\\ !!! This is one of two listeners that will respond to this event");
    }
    myListener.onGetGoogFeedError = function(obj) {
    trace ("\\ ERROR was returned");
    }
    remote.serve("Do_Test", 0, "mystring");
    NetDebug.trace("test to debugger");
    *******
    For some reason, the NetDebug.trace() still doesn't work. Am I missing the boat on this one?
    I tried using the UF "com" libraries in their own class path, adding them to my default class path, and even replaced the "mx.remoting" files with the ones given here, but still no love!
    Something is alluding me. :(

  13. Brian Grayless  Replied:
    ( 3/16/2005 At 1:50 AM)

    Finally figured it out. I didn't have to do the this when I did remoting on the last project (using the AS1.0 remoting libs), but I needed to drag the RemotingDebugClasses onto the stage, then delete it from the stage. The panel was found at Window->Other Panels->Common Libraries->Remoting
    Thanks for pointing me in the right direction.
    Brian

  14. Aran Rhee  Replied:
    ( 3/16/2005 At 7:40 AM)

    Brian.
    Glad to hear you worked it out.
    BTW - you would be interested to know that you don't have to drag and delete an instance if you download the classes directly. In one of my early posts, I made reference to it:
    http://download.macromedia.com/pub/flashremoting/mx2004/components/actionscript_2.0/flashremoting_comp_sourcecode.zip
    download this file and extract to:
    C:\\Program Files\\Macromedia\\Flash MX 2004\\en\\First Run\\Classes
    (safe to overwrite files if asked, but I don;t think it does by memory...)
    You can then just use include statements to the classes you specifically want without having to include ALL classes through adding the remoting connectors (good file size savings, and a removal of uneccessary steps).
    readme about install here: http://www.macromedia.com/support/documentation/en/flash_remoting/mx2004/readme_source.html
    Go well on your project,
    Aran

  15. Aran Rhee  Replied:
    ( 3/16/2005 At 8:27 AM)

    Jed / Brian.
    This article got me thinking how I didn't like the regular way I was working with remoting. I started off by rewriting Jed's code using the MM AS2 classes, rather than Joey’s to bring it inline with the rest of my app(s).
    I have now written a beta version of a remoting manager singleton which takes some elements of the UFcache and ideas about dispatching events rather than using relay Responders (so multiple listeners can fire events on a result return). I have incorporated a queuing system, so that you can add multiple remoting calls and have them fire in order. (based on some code I found on a German flash forum)
    Are you interested in collaborating to improve the manager?
    Just to give you an idea of how it works (sorry if the formatting gets mangled):
    import com.qdc.remoting.*;
    class someLoginEG
    {
    private var rm:RemoteManager;
    public function someLoginEG()
    {
    rm = RemoteManager.getInstance();
    rm.setGatewayUrl("http://some/remoting/gateway");
    rm.addEventListener("ALL", this);
    }
    private function connect (aHost:string, aDB:string, aUser:string, aPass:string)
    {
    // addcall(java/.net class, method name, [successEvent, failureEvent], params)
    rm.addCall("com.qdc.login.LoginClass", "connect", ["onLoginConnect", "onLoginError"], aHost, aDB, aUser, aPass;
    // addCachedCall(java/.net class, method name, [successEvent, failureEvent], {save to cache, data lifespan}, params)
    rm.addCachedCall("com.qdc.otherClass", "doSomething", ["someEvent", "someError"], {cache:true, time:5}, aParam, aParam2);
    }
    private function onLoginConnect(msgObj:Object)
    {
    trace ("success - data was: "+msgObj.result);
    }
    //etc ...
    }
    At present the remoting manager creates a new instance of a remoteCall object (another custom class) which holds all info about its own arguments, method name, cache object, parent service etc. for each add(Cached)Call. These objects are then processed in the queue.
    I am looking for feedback on the classes (coding best practices etc.) and usability from people who use remoting regularly.
    If you think you could contribute (or know someone who would), please let me know.
    Cheers,
    Aran

  16. kalel  Replied:
    ( 4/7/2005 At 11:34 PM)

    I have the new remoting components but I installed flash remoting MX and realized its just a gateway add on for .net or java.
    I don't have a flashservices folder in my webroot (iis) where do I get the flash remoting files?
    Thanks

  17. Aran Rhee  Replied:
    ( 4/8/2005 At 4:05 AM)

    Kalel.
    Just to clarify, are you saying that you already have the flash MX remoting components (Actionscript files) and you just installed flash remoting for .NET (server-side)? If you did install .NET remoting (I'm assuming you are using the 30 day trial), then you should have the two parts required for remoting:
    1. Actionscript classes / functions on the client side for use within flash. These are free and provided by macromedia for both mx (AS1) and MX2004 (AS1 or AS2).
    2. Serverside gateway. This depends on the server-side language you desire. If you want .NET capabilities, you only have two options (both commercial) - either Macromedia's implementation, or flashOrb .NET. If you have installed MM's .NET remoting, it creates a dir here by default: "C:\\Inetpub\\wwwroot\\flashremoting". You specify the .aspx file in that dir like: "http://localhost/flashremoting/gateway.aspx" as your gateway in your flash app.
    There are open source projects for java and .php serverside remoting gateways.
    Hope that hekps,
    Aran

  18. Kollins Joe  Replied:
    ( 4/26/2005 At 2:45 PM)

    hello gurus,
    I so much appreciate all the efforts gurus are putting in developing and educating other flash users.
    Just a couple of months ago, i picked interest in flash. But it seems to me i still have a long way to go.
    i ventured into creating an electronic album that can have some visual effects, which can also display biodata of all the people involved from a database file.
    I'm at the moment at the middle of the project, but don't know how to display all the pictures at the same time.
    Please, Somebody should come to my aid. through my email address.
    Thanks for being a friend.
    Kollins

  19. Nuno Ribeiro  Replied:
    ( 6/22/2005 At 2:25 PM)

    First, congratulations to Jed for the work he's done on this page. I'm a beginner in some aspects of Flash.
    I was reading this article and I realize one detail that i think we must not forget: the data limit for Shared Objects. In this article Jed uses SO's to store the data retrieved by a web service, but nobody has asked if the returned data exceeds 100k.
    In my opinion the initial idea from Jed is quite cool and useful, but in practice it may not work. In the SO specification we can see that by default the maximum size of a SO is 100k. If the size we try to save in a client computer is higher than this value, the user is presented by a panel where he can define the size of the SO. (Which, in my opinion, is inelegant).
    I thought, why not develop a scheme that uses the initial idea from Jed, but stores the information in some other way? So, I'm now trying to develop a kind of RemoteManager that uses Jed's ideas but stores the information in memory.
    If you have time, please comment on my ideas.
    Thanks,
    Nuno Ribeiro

  20. Aran  Replied:
    ( 6/23/2005 At 4:16 AM)

    Nuno,
    When you say "Stores the information in memory," are you talking about storing it in RAM (i.e. Flash Player variables and objects)?
    I don't quite understand how or where you could store this 100+KB without calling a server to retrieve it again, which is the whole point of Shared Objects in the first place.
    Can you please explain your intended system a bit more? The Flash SO is really the only way to prevent roundtrips to the database or webservice that would normally have to occur. Of course, you can store any amount of data in Flash Player memory (as long as you have RAM), but as soon as the movie is unloaded, that data is gone.
    100K IS quite a lot of data, btw, especially for a Flash app (102400 characters!). What are you expecting to store?
    Cheers,
    Aran

  21. Nuno Ribeiro  Replied:
    ( 6/23/2005 At 1:41 PM)

    Aran,
    I think I forgot one important thing: the purpose of using a SO. After read your post, I remembered that Shared Objects are the Flash Player equivalent to cookies.
    So, just like cookies, they are used to store small amounts of data.
    After reading this I think you get my point, and you're right when you say "...how or where you could store this 100+KB without calling a server to retrieve it again, which is the whole point of Shared Objects in the first place."
    When I say store data in memory, my idea is to store the info in RAM (i.e. Flash Player variables and objects).
    Perhaps when I wrote the first post, I forgot some important concepts.
    Just to clarify one thing because, like I mentioned, I'm a beginner... how do you prevent a web service call if the returned data is more than 100KB? I don't know if I'm going to use this approach, but if you can, please clarify my thinking.
    Thanks.
    Nuno

  22. Aran  Replied:
    ( 6/24/2005 At 3:50 AM)

    Nuno.
    Not a problem. I just didn't fully understand what you were wanting to do.
    Prevent a call if > 100KB: Sounds like you don't actually want to prevent the call, but prevent the storage of it if it is that large. As you said, you can still store it in RAM.
    You probably just want to check the number of records returned and only store whatever's necessary in the SO.
    A 100kb dataset is really going to kill the responsiveness of your app, so I would suggest breaking into smaller parts, especially if any users are going to be on dial-up.
    Cheers,
    Aran

  23. Nuno Ribeiro  Replied:
    ( 6/28/2005 At 2:02 PM)

    Aran,
    I have been working on a project where I use Web services, and after I read and posted the previous comments, I made a choice based on one of your comments, and the Jed Wood article.
    I'm working on a RemoteManager that is a singleton class (your idea). In this class I have a queue where I put the Web services, and I have a kind of mechanism that simulates a thread (Java, C#, etc.). When I have Web services in the queue, I dispatch them using this mechanism. The mechanism is built using the setInterval and clearInterval functions provided by Flash.
    When I store one or more services in the queue I make a call to the function that dispatches them. When the queue is empty, I clear the interval to avoid an infinite loop.
    The function that dispatches the service calls uses a variation of the 'Business Delegate' pattern (BD). I remove a Web service from the queue, and delegate the work that it is suposed to do, to a BD class. I have three BD classes because I have three diferent types of call, as you can see below. These business delegate classes have a method execute() that is responsible for executing the service call. All the three classes implement the IBusinessDelegate interface.
    Using this RemoteManager I can decide where to store any results; memory, or cache, or none.
    The code to execute a Web service is:
    RemoteManager.getInstance().setGatewayURLgatewayURL);
    webService = new WebServiceWrapper(1, serviceURL, "GetMenu", "wsMenuGetMenu_Result", "wsMenuGetMenu_Fault", 0.5, 1, "PT");
    RemoteManager.getInstance().addWebService(webService);
    RemoteManager.getInstance().addEventListener("ALL", this);
    /*new WebServiceWrapper(key, name, methodToInvoke, onSuccesFunction, onErrorFunction,
    timeToStore, typeOfCall, arg1,...,argn);
    */
    timeToStore - same as cache time.
    typeOfCall - 0 -> normal web service call (no storage).
    1 -> store the result in cache.
    2 -> store the result in memory.
    Now I'm working on a 'Service Locator' class (Service Locator pattern) to find the Web services.
    The code I have been working is based on your idea, and uses the Jed Wood cached storage mechanism.
    To develop the functionality that stores the information in memory, I'm using a hash table.
    When you have time, comment on my ideas.
    If you want, I can explain further anything you doubt.
    Compliments,
    Nuno Ribeiro

  24. Aran  Replied:
    ( 6/29/2005 At 9:05 AM)

    Nuno,
    I understand perfectly what you are trying to achieve. You are pretty much doing exactly what I felt I needed to do after reading Jed's article (except for Web services rather than remoting).
    If you email me directly we can continue from there.
    Cheers,
    Aran

  25. Nuno Ribeiro  Replied:
    ( 7/11/2005 At 2:35 PM)

    Hi.
    I just have one more ideia/suggestion.
    Why don't we use an Cryptography Algorithm to cypher the content that we save in an SO?
    Sephiroth (http://www.sephiroth.it/) has build a software that can read the content of SO. If we use one algorithm for cypher the content, only the person who build the SO can read the data from it.
    There are several algorithms, Meychi (www.meychi.com) has an framework based on those kind of algoritms.
    Cheers,
    Nuno Ribeiro

Login to post your comments. If you do not have an account with us please Register.
Copyright 2005 by ActionScript, Inc.   |  Privacy Statement  |  Terms Of Use  |  ActionScript Client Extranet