Too much redundancy and overhead for declaring the remote methods in your flex application. I don't want to receive the same ResultEvent object, I want to receive my own objects I also want to centralize my error handling code for both Flex Error or explicit error return by the remote server
Using a singleton Service class to centralize your remote invocation. Using closure to execute your onResult function and return what you're interested in
Note: The below code is particularly implemented on the context of using BlazeDS and Spring Framework.
Here is my Service class
package service {
import flash.display.Sprite;
import mx.controls.Alert;
import mx.core.Application;
import mx.rpc.AbstractOperation;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.remoting.mxml.RemoteObject;
import vo.MessageServiceResponse;
import vo.ServiceResponse;
public class Service {
/**
* Singleton
*/
private var _this:Service = null;
/**
* Map operation->Function
*/
private static var listeners:Dictionary = new Dictionary();
/**
* The remote object to do remote invocation
*/
private var remoteObject:RemoteObject = new RemoteObject("myRemoteObject");
public function Service() {
new SingletonEnforcer();
}
public static function instance():Service {
if (_this == null) {
_this = new Service();
// Initialize the remote object
remoteObject.addEventListener(FaultEvent.FAULT, _this.onFault);
remoteObject.showBusyCursor = true;
}
return _this;
}
/**
* Wrapper for onResult function, to resolve any internal error that is returned by remoteObject
*/
private function onResultWrapper(event:ResultEvent, onResult:Function):void {
var serviceResponse:ServiceResponse = event.result as ServiceResponse;
if (serviceResponse != null) {
if (serviceResponse.status == -1) {
alertFault(serviceResponse.message);
} else {
onResult(serviceResponse);
}
} else {
alertFault("Invalid response object");
}
}
/**
* Mainly communication fault
*/
private function onFault(event:FaultEvent = null):void {
alertFault("Server communication failed");
}
/**
* Display error message
*/
public function alertFault(msg:String):void {
Alert.show(msg, "ERROR", 4, Sprite(Application.application), null, null);
}
/**
* Sample remote method
*/
public function helloWorld(onResult:Function):void {
getOperation("helloWorld", function(resp:MessageServiceResponse):void {
// return only what I want
onResult(resp.msg);
}).send();
}
private function getOperation(methodName:String, onResult:Function):AbstractOperation {
var op:AbstractOperation = remoteObject.getOperation(methodName);
if (op == null) throw new Error("No such remote method name: " + methodName);
if (!op.hasEventListener(FaultEvent.FAULT)) {
op.addEventListener(FaultEvent.FAULT, onFault);
}
var listenerFunction:Function = listeners[methodName];
// remove the old listener
if (listenerFunction != null) {
if (op.hasEventListener(ResultEvent.RESULT)) op.removeEventListener(ResultEvent.RESULT, listenerFunction);
else delete listeners[methodName];
}
listenerFunction = function(event:ResultEvent):void {
onResultWrapper(event, onResult);
};
listeners[methodName] = listenerFunction;
op.addEventListener(ResultEvent.RESULT, listenerFunction);
return op;
}
}
}
class SingletonEnforcer {}
The ServiceResponse class is as follow
package vo {
[Bindable]
[RemoteClass(alias="myapp.mypackage.ServiceResponse")]
public class ServiceResponse {
public var status:int;
public var message:String;
public function ServiceResponse() {}
}
}
It's a good practice that any other service response must extend this class. E.g.: MessageServiceResponse, UsersServiceResponse, RolesServiceResponse ....
package vo {
[Bindable]
[RemoteClass(alias="myapp.mypackage.MessageServiceResponse")]
public class MessageServiceResponse extends ServiceResponse {
public var msg:String;
public function MessageServiceResponse() {}
}
}
And this is how to call the method
Service.instance().helloWorld(service_onResult);
service_onResult is an user-defined function to process the results that are returned successfully
/**
* Accept only what i need
*/
private function service_onResult(msg:String):void {
Alert.show(msg);
}
Cons: One of the potential pitfalls is if the operation is invoked twice and simultaneously then it may cause unexpected result.