Web Services in Flash and ActionScript 3


In some ways, I understand, but in most I do not.  For some reason Adobe removed web services from ActionScript 3 in Flash.  The web services classes we all used in AS 2 with abandon for no longer exist in the Flash API.  Wow.  This post offers up my research on getting around this issue.


Time was you could import these classes:

import mx.services.WebService;
import mx.services.SOAPCall;
import mx.services.PendingCall;

And you still can, if you change your ActionScript version to 2.0 in the Publish Settings for your project.  However, if you’re like me and your project relies on new components only available in ActionScript 3, then that is not an option.  You’ll get an error, “1172: Definition mx.services:WebService could not be found.”  You may also be able to get past that and still get “1046: Type was not found or was not a compile-time constant: WebService.”  These classes are avialble to you if you’re developing in Flex or AIR with AS3.  Apparently, Adobe only wants you creating rich internet applications with Flex or AIR.  Of course, this also means that you cannot take any Flash app which uses these classes and upgrade them to AS3.

When I finally discovered this cause of this problem (BTW: I have only found it mentioned on other blogs, not from Adobe) I have to admit I paniced for a minute.  Then, I got creative…  I thought about moving the forms to individual Flex projects and embedding the resulting SWFs, I thought about calling out HTML popup windows, and I thought about trying to redevelop the application in Flex – big problem with that being that the Flash developer had already created a beautiful interface full of graphics.

Then, I disovered two workarounds which do not require opening up my Flex Builder.  One option is to include a custom component specifically developed to get around this problem.  You can find it here.  This method is particular useful if you were used to dropping in the WebServiceConnector from the Componets panel.

The other method, and the one I chose because I prefer to use ActionScript, is to make use of the URLRequest, URLLoader, and URLVariables classes available in AS3.  I grabbed the open source AS3 CoreLib off of Google Code and used its JSON serialization method.  I did end up dropping the strict WSDL, but you could still use one if you needed to.  The tutorials I found on this method centered on retrieving data from a web service, but I was submitting information with a form.

Here’s my JSONService class I created to help:

package {
	import flash.events.Event;
	import flash.net.URLRequest;
	import flash.net.URLLoader;
	import flash.net.URLVariables;
	import flash.net.URLRequestMethod;

	/* JSON
   	used for communicating data with PHP tier
   	grab AS3 CoreLib from http://code.google.com/p/as3corelib/downloads/list
   	and make sure the "src" folder from the extracted zip is in your class path
	*/
	import com.adobe.serialization.json.JSON;

	public class JSONService {
		private var serviceAddress	:String;

		public function JSONService ( address:String ) {
			serviceAddress = address;
		}

		public function sendRequest (func:String, container:String, packet:Object) {
			/* encode and prepare the data for transfer */
			var jsonString:String		= JSON.encode(packet);
			var urlVars:URLVariables	= new URLVariables();
			urlVars[container]		= jsonString;

			var urlReq:URLRequest		= new URLRequest(serviceAddress + "?request=" + func);
			urlReq.method 			= URLRequestMethod.POST;
			urlReq.data			= urlVars;

			/* make the actual call */
			var urlLoader:URLLoader		= new URLLoader();
			urlLoader.addEventListener(Event.COMPLETE, this.sendCompleteEvent);
			urlLoader.load(urlReq);
		}

		public function sendCompleteEvent(evt:Event) {
			// trace(evt.target.data);
			if(evt.target.data != 1) {
				/* error reported by backend */
				var error:Object = JSON.decode(evt.target.data) as Object;
				trace(error.message);
			} else {
				/* send successful */
				trace('success');
			}
		}
	}
}

When I use this class, I call it with:

service = new JSONService(config.getLoadVar("wsdl"));

service.sendRequest("add_contact", "contact", contactObject);

Which reminds me, they also got rid of LoadVars.  I combined the information in this post and with my JSONService class to create a configData singleton.  At any rate, contactObject contains all the properties I am sending to the “add_contact” method in my RESTful controller (a PHP file in this case).  The contents of contactObject are JSON encoded and placed in the contact container URL variable as part of the request.

Behind the scenes, a PHP MVC (model-view-controller) application stores the data.  The PHP file which handles the request looks like:

$request = @$_GET['request'];

switch ( $request ) {
    // lots of other request handlers...
    // handler for add_contact
    case 'add_contact':
        if ( !isset( $_POST['contact'] ) ) {
            echo jsonFault( -1000, 'Improperly Formatted Request' );
        } else {
            $response = $controller->addContact($_POST['contact']);
            if ( $response == 1) {
                echo json_encode( 1 );
            } else {
                echo jsonFault( -2000, model::getErrorMessage( $response ) );
            }
        }
        break;
}

function jsonFault( $code, $message ) {
    $fault = new stdClass();
    $fault->isFault = true;
    $fault->code = $code;
    $fault->message = $message;
    return json_encode( $fault );
}

The $controller object decodes the JSON packets and performs some action, such as validation and handing them off to the model class for storage.

I should also note that I have since found this article, which provides a nice AS3 object to download and use.



Comments are closed.