As I said earlier, it’s not a huge bug, but artf5612, the bug about Flex importing the web service with arguments in the wrong order, was bothering me, so I did some research and testing. The situation is far more complicated than it appeared.
As it turns out, WSDL allows you to use two different binding styles and two different uses. The RPC (Remote Procedure Call) binding style is more intuitive, but the document binding style has the advantage that it passes XML validation. The literal use versus the encoded use seems to be mostly about whether type info is included in the SOAP messages on top of the WSDL file (encoded) or not (literal).
NuSOAP uses RPC/encoded unless you specify otherwise. Apparently, while RPC/encoded is (technically) valid WSDL, it’s not WS-I (Web Standards Interoperability Organization) compliant. Document/encoded isn’t used, which leaves just RPC/literal and document/literal. Both of these are WS-I compliant, but RPC/literal may be deprecated in the future. Document/literal is, in any case, the preferred way of doing WSDL.
I have changed our SOAP service so the createUser operation is registered as document/literal, and I think I’ll commit this, but I’m a bit wary of document/literal, frankly. It has a massive (in my opinion) disadvantage, in that the operation name is lost. This means that the only way to tell which function should be called using document/literal is to check the number and type of parameters it takes. And that means that if you have two functions that take the same number and type of parameters, it’s impossible to tell which function to dispatch to.
Having said that, it “fixes” the bug, although it requires even MORE ActionScript to be generated than RPC/encoded did, and that was already 4 files plus 2 for each operation. Document/literal will require 4 + 4/operation apparently, because in addition to the XResultEvent and the X_request.as files, we now also get a XRequestType and XResponseType, which are classes that “wrap” the request and response. This results in a somewhat different and, in my opinion, less intuitive code style. But supposedly it is the better way, so I guess we’ll deal with it.
In other news, Professor Danneels apparently is reading my blog, despite the mostly technical content. He just e-mailed us saying it seems like a good idea to ask users for their real name and an e-mail address, which is a good thing because I’ve already (re-)implemented some stuff under that assumption.
Pingback: Flex Sucks: Greatest Hits! « CaptainRichard's Blog
I have found that it only changes the order if there is more than one parameter (obviously) and if there is a parameter of a self-defined complex type (e.g. “tns:User”) before standard types (e.g. “xsd:string”).
If you make sure to put the parameters that are of a complex type as your last parameters, the order should now show up correctly in Flex.
So, intead of, say:
// register a web service method
$server->register('addInstitution',
array('institution' => 'tns:Institution','username' => 'xsd:string','password_hash' => 'xsd:string'),
array('luhn_key' => 'xsd:string'),
$ns,
"$ns#addInstitution",
'rpc',
'encoded',
'inserts an institution into the db and returns success'
);
function addInstitution($institution, $username, $password_hash,)
{
// code here
}
change it to:
// register a web service method
$server->register('addInstitution',
array('username' => 'xsd:string','password_hash' => 'xsd:string','institution' => 'tns:Institution'),
array('luhn_key' => 'xsd:string'),
$ns,
"$ns#addInstitution",
'rpc',
'encoded',
'inserts an institution into the db and returns success'
);
function addInstitution($username, $password_hash, $institution)
{
// code here
}
Using the parameter Institution defined as:
$server->wsdl->addComplexType(
"Institution",
"complexType",
"struct",
"all",
"",
array(
"institution_key" => array("name"=>"institution_key","type"=>"xsd:string"),
"email" => array("name"=>"email","type"=>"xsd:string"),
"luhn_key" => array("name"=>"luhn_key","type"=>"xsd:string"),
"is_activated" => array("name"=>"is_activated","type"=>"xsd:boolean"),
"expires" => array("name"=>"expires","type"=>"xsd:dateTime"),
"max_num_seats" => array("name"=>"max_num_seats","type"=>"xsd:int"),
"domain_space" => array("name"=>"domain_space","type"=>"xsd:string")
)
);