Need Flex Migration Help?
- Adobe ends Flash player support in 2020
- Flex apps will no longer function
- We can help migrate your app
A customer of mine found a bug my AS3 DataManager when making multiple simultaneous calls. Here is the fix to the bug.
The issue is that while the DataManager allows calls to many methods in a web service, each instance of the DataManager only has a single eventName property. I was able to work around this by making use of hte AsyncToken, which is returned whenever a call to an AbstractOperation (such as a WebService) is made. The AsyncToken is carried along with the request and available when results happen as part of the ResultEvent. Even better, its a dynamic class, so you can add any arbitrary properties on it you want. So, to fix the issue, replace the existing makeRemoteCall method with this:
public function makeRemoteCall(methodName:String,eventName:String, args:Object):void{
trace("DataManager.makeRemoteCall("+methodName+","+eventName+","+args+")");
this.eventName = eventName;
var op:mx.rpc.AbstractOperation = ws[methodName];
ws.addEventListener("result",doResults);
ws.addEventListener("fault",doFault);
if(args){
op.arguments = args;
}
var token:AsyncToken = op.send();
token.eventName = eventName;
}
private function doResults(event:ResultEvent):void{
var e:DataManagerResultEvent = new DataManagerResultEvent( event.token.eventName, event.result);
this.dispatchEvent(e);
}
Now, the event names is stored with the request, so we have access to a different event name for each request made! The completed code looks like this:
package managers {
import flash.events.EventDispatcher;
import mx.rpc.soap.WebService;
import mx.rpc.events.ResultEvent;
import mx.rpc.events.FaultEvent;
import mx.rpc.AbstractOperation;
import events.DataManagerResultEvent;
import flash.util.*
import mx.rpc.AsyncToken;;
/** DataManager - singleton class which enforces only
a single object is created for eachwsdl. To
access DataManager, use getDataManager(wsdl:String) */
public class DataManager extends EventDispatcher {
private var ws:WebService;
private var eventName:String;
// hashmap of instances for each wsdl
private static var instanceMap:Object = new Object();
private static var methodEventMap:Object = new Object();
public function DataManager(pri:PrivateClass, wsdl:String){
this.ws = new WebService();
ws.wsdl = wsdl;
ws.loadWSDL();
ws.useProxy = false;
}
public static function getDataManager(wsdl:String):DataManager{
if(DataManager.instanceMap[wsdl] == null){
DataManager.instanceMap[wsdl] = new DataManager(new PrivateClass(),wsdl);
}
var dm:DataManager= DataManager.instanceMap[wsdl];
if(dm.ws.canLoadWSDL()){
return dm;
} else {
throw new Error("BAD WSDL:"+wsdl);
}
}
public function makeRemoteCall(methodName:String,eventName:String, args:Object):void{
trace("DataManager.makeRemoteCall("+methodName+","+eventName+","+args+")");
this.eventName = eventName;
var op:mx.rpc.AbstractOperation = ws[methodName];
ws.addEventListener("result",doResults);
ws.addEventListener("fault",doFault);
if(args){
op.arguments = args;
}
var token:AsyncToken = op.send();
token.eventName = eventName;
}
private function doResults(event:ResultEvent):void{
var e:DataManagerResultEvent = new DataManagerResultEvent( event.token.eventName, event.result);
this.dispatchEvent(e);
}
private function doFault(fault:FaultEvent):void{
trace("DataManager.doFault("+fault.fault.faultString+")");
this.dispatchEvent(fault);
}
public override function toString():String{
return "DataManager";
}
}
}
/** PrivateClass is used to make DataManager constructor private */
class PrivateClass{
public function PrivateClass() {
}
}
What if I have a Web Service that not only has complex types but a choice? So basically I don’t have simple parameters to pass. I need to specify or pass in a whole custom build XML structure to be passed as the request. Is this possible with AS3?
Thanks for the time and response. I am having trouble finding an answer to this else where.
I’m still having a problem, even after updating my code. I am creating the WebService twice within the same application, and it is failing to return the result. If I take out either of the WebService calls, it works. Any suggestions?
My code (this DOES NOT work for me):
// Start retrieving the lists of data needed to build the form options/inputs
private function init():void
{
var wsReports:webservices.wsCreate;
wsReports = wsCreate.getWebService(“/private/cfc/get_reports.cfc?wsdl”);
// Create an event listener for the result from the WebService
wsReports.addEventListener(“reportsResult”, reportsResult);
// Create an event listener for any faults from the WebService
wsReports.addEventListener(FaultEvent.FAULT, faultEvent);
// Call the WebService
wsReports.makeRemoteCall(“get_reports”, “reportsResult”);
}
// Handle the object returned from the Reports WebService
private function reportsResult(evt:wsResultEvent):void
{
// Create an XML object to store the results of the WebService call
var reportsXML:XML = new XML(evt.result as Object);
reportSel.dataProvider = reportsXML.report;
var wsReportFilters:webservices.wsCreate;
wsReportFilters = wsCreate.getWebService(“/private/cfc/get_report_filters.cfc?wsdl”);
// Create an event listener for the result from the WebService
wsReportFilters.addEventListener(“reportFiltersResult”, reportFiltersResult);
// Create an event listener for any faults from the WebService
wsReportFilters.addEventListener(FaultEvent.FAULT, faultEvent);
// Call the WebService
wsReportFilters.makeRemoteCall(“get_report_filters”, “reportFiltersResult”);
}
Nevermind, I found my problem – I still had the parameter typed to be a “ResultEvent” in my event handler function, instead of a “wsResultEvent”. I have this working now like a charm! Thanks again for this great app.
I did all the things what you have shown in post. It is working fine. But my only problem is, the result of DataManagerResultEvent is returned as ObjectProxy not as a XMLLIST. But it was returning XMLLIST before changed the code. I have used resultFormat=”e4x”. Please help me to solve this problem. This is realy important thing.
Thank You
Sanjaya