We're starting to use XUL to make nice interfaces, and encountered a bitch of a problem getting our javascript code
running on the client to talk nicely with our .NET web services. The good folks at
Mandragor & Apinc posted some really great content about
creating applications with Mozilla,
with a chapter on
remote applications.
That has a section on using javascript to call .NET web services. I thought "Great, thats precisely what I want to do, and here's a code sample."
Unfortunately, the law of code samples off the web (sample code will never work, ever) still applied.
When the javascript sent the SOAP request, it's XML was formatted ever so differently, and the web
service didn't like it. The web method would get called, but no data
would be passed in. It was fun to see my breakpoint being hit for the first time, but quite
disheartening to see every input was
0 or
null. Some snippets:
Here's the bad javascript code (simplified a little for clarity) that generated the bad XML:
...
//code from the tutorial
var params = new Array(
new SOAPParameter(this.contactId,"contactId"),
new SOAPParameter(this.comments,"comments")
);
//rest of the call from the tutorial
...
After looking at some of the documentation on the
SOAPCall object,
this all made reasonable sense. I thought having the
SOAPParamter constructor take value before name was an odd choice, but whatever. Here's the generated XML:
...
<a0:AddComment xmlns:a0="uri:Comment">
<contactId>2</contactId>
<comments>this is my comment</comments>
</a0:AddComment>
...
We thought the "a0" business was a little odd, but figured the purpose of these SOAP objects was to abstract out those details and just do it right.
So we spent a day of trying different meaningless tweaks, finding new debugging tools, cursing, and reading endless articles on
XUL web services objects,
WSDL,
HTC,
RDF, and
god knows what else.
Finally, we figured it out. The problem was with the
SOAPParameters,
and that little "a0" was the culprit. The
SOAPParameter has a
namespaceURI property that had to be set as well.
After adding a helper function, here's the corrected code:
function getParam (value, name, namespaceURI){
var parm = new SOAPParameter(value, name);
parm.namespaceURI = namespaceURI;
return parm;
}
...
//code from the tutorial
var params = new Array(
getParam(this.contactId,"contactId", "uri:Comment"),
getParam(this.comments,"comments", "uri:Comment")
);
//rest of the call from the tutorial
...
Now the generated XML has all the namespaces fixed:
...
<a0:AddComment xmlns:a0="uri:Comment">
<a0:contactId>2</a0:contactId>
<a0:comments>this is my comment</a0:comments>
</a0:AddComment>
...
The a0s make all the difference, and now it all works perfectly. As a bonus, we found some excellent tools:
-
LiveHTTPHeaders - Firefox plugin to view HTTP headers for requests and reponses.
-
Venkman - Javascript debugger for Mozilla based browsers, letting you step through code, etc.
-
XulRef - Firefox plugin to display a XUL reference in the sidebar, with links to the documentation.