|
I've said it many times before and I'll continue to say it - I hate WSDL. I've never liked the standard and I've always thought it was overly complex. I don't like the idea of adding layers of complexity that introduce friction in the development process when there are easier, simpler ways of accomplishing the same task.
Don't get me wrong, there are a lot of people who have a valid need for all of those WS-* standards and once you get into that kind of complexity then yes, stuff like WSDL seems like a necessary evil. But when all I want to do is have a web server hock up some data that my client application can display for the user and allow them to interact with it, it seems like needless bloat to me.
So anyway, first thing I tried to do was create a stub Objective-C class that wraps around my web service. I was actually pretty surprised to find that there is a tool that lets you do this, it's called WSMakeStubs and you run it from the command line (reminds me of the old days of dropping down and firing up soapsuds from the command line in .NET 1.0). And yes, for those of you unfamiliar with .NET, there really was a SOAP dissection tool called soapsuds.
Here's the command line that I issued from inside terminal:WSMakeStubs -x ObjC -name SampleService -url http://mybox/webservice1/service1.asmx?wsdl
This gave me a class called SampleService that derived from another class that contained all of the plumbing code to communicate with the web service.
Great!, I think to myself. I'll just add these bad boys to my Xcode project and then rig up a controller, set up some bindings in IB and we'll be good to go. No dice.
When I added the class files to the project, and made sure I had the WebservicesCore framework available to my project and I attempted to build - I got 10 errors and 6 warnings. So I took a quick look. My web service has two methods, "HelloWorld" and "GetPeople", returning a string and an array of strings respectively. First thing I notice is that the generated class header had defined interfaces for each method, twice. Then I noticed that it implemented each of those classes twice.
Then I found a page on Wikibooks that tells me that there are memory leaks in the generated web services stub code, so I follow some of that, but unfortunately some of the code it says I'm supposed to replace doesn't exist in my generated code.
Now that my code is finally compiling I have a class called Service1Service and it has static methods on it, one of them is called GetPeople, so I figure I can do the following (given that there are no arguments to my GetPeople method):
id result = [Service1Service GetPeople:NULL];
But nope. This doesn't work, some kind of complaint about a dictionary getting a nil item inserted into it at runtime prevents anything from happening. So I figure I'll check the Apple documentation ... but the web services core documentation doesn't actually show you HOW to use classes generated by WSMakeStubs.
Knowing how good Apple is with samples, I take a look at their sample code. Sure enough, in /Developer/Examples/WebServices/XmethodsInspector, the README.txt there informs me that this is an example of how to use code generated by WSMakeStubs in Cocoa... problem is, the sample doesn't actually contain generated code from WSMakeStubs, and there are no instructions on what the command line should be for generating the stubs. Obviously when you attempt to build this sample, it fails miserably.
So I decide to look at the code. Turns out, in this sample, when you want to execute a method on the service with no params, you just invoke the method name without any parameters. When I attempt to do that, I end up with the expected warning about Service1Service not being able to respond to a method called 'GetPeople'.
So at this point I'm left with absolutely zero documentation from Apple on how to use code generated by WSMakeStubs, no mention from them as to why the generator failed and created 2 copies of each (though I suspect this is because the host WS is publishing both regular GET and SOAP methods with the same name). The sample for WSMakeStubs is missing the stubs(!!!) and won't compile, and all the public information I can find about WSMakeStubs refers to bugs in the generated code, not actual samples for invoking it.
Conclusion: Come on people, this is web services. This crap is completely ubiquitous and Microsoft tools have been able to right-click and "Add Web Service Reference" for years now, and it's a ridiculously smooth experience. The WSMakeStubs tool is still version 0.2 and hasn't been updated or modified once since it was originally released back in the good old days. I realize that WSDL sucks, but some people actually need to do it, and making it this much of a pain in the ass to do it from Cocoa doesn't make me want to write Mac-based web service clients.
Before you Cocoa people flame me for this, I realize that there is probably
some 30-line set of code you can call on WSGeneratedObj to invoke the web
service... but I am coming at this from the point of view of a .NET
developer with years of Web Service development. When I use a tool to
generate web service stubs on it, I fully expect that it will have methods
that correspond to server-side methods that I can invoke quickly and easily
without any hassle, and certainly without referring to SOAP anywhere in my
invocation.
The WS support in cocoa is based on circa 2001 rpc/encoded soap, even if
you got your stub working, chances are its not going to work with the web
service anyway, between the bugs and lack of features (missing parts of the
http headers, numerous options in the WS classes don't do anything etc) its
not worth the hassle.
Fortunately, there's a reasonable xml parser and HTTP stack, so its fairly
easy to just whip up your own stub. (this is what i ended up doing). I
think this underscores Apple's disinterest in the enterprise market.
That's complete crap. Desktop applications are spending more and more time
consuming services from the Internet, including web services and the
overused buzzphrase of "Cloud services". I can't believe that Apple would
completely drop the ball and leave developers in the lurch when it comes to
web services when they provide so many other ridiculously powerful APIs.
What about generating a client-side WSDL proxy in Mono/C# and then doing
some kind of Cocoa-mono bridge to invoke it? Is such a thing even possible?
I would love to see an example of this if someone knows where I could find
it.
Ever consider REST? I don't know what kind of support there is in
ObjC/Cocoa, but it might be a simpler way to go...
Of course I've considered REST, and I know that it's really easy to bust
out a RESTful POX client in Cocoa using just NSUrl and the XML parsing
classes... But that's not the point. The point is that the rest of the
world may not be as forward-thinking as those of us who actually create
RESTful services. There is a lot of legacy code and even new code in WSDL
out there and Apple seems to be unsupportive of people who want to access
WSDL services.
I found some documentation that shows how you can use the ObjCsharp bridge
in the mono framework to invoke .NET methods through mono, but in typical
OSS fashion, they show you a couple lines of code and expect you to be a
contributor so you know exactly how to integrate the ObjCsharp stuff into
your Cocoa app. If anybody knows how to do this, I would love it if you
could drop me a hint!
I'm guessing that Apple's efforts around WS-* have largely been
concentrated on WebObjects, but even so that's more about producing than
consuming.
Exactly. One can assume without knowing anything about the iPhone SDK that
if the experience of consuming WSDL services from Cocoa on Leopard is a
huge pain in the ass, it's going to be even worse on the iPhone due to it
being a subset of Leopard.
a lead you can explore:
WSMakeStubs hasn't entirely been left alone; one sign of that is
illustrated by the difference between what it generated and what that
Wikibook showed. Also, since WebServicesCore is part of the CoreServices
umbrella framework that's what you should link, not WebServicesCore.
The WSMakeStubs tool hasn't entirely been left alone; one
sign of that is illustrated by the difference between what it generated and
what that Wikibook showed. Also, since WebServicesCore is part of
the CoreServices.framework umbrella framework that's what you
should link, not WebServicesCore.framework itself.
Thanks Kevin for lifting this subject. I have spent years wondering of the
lack of connection between Apple/Cocoa/WebServices. The result: I dropped
Cococa developemt altogehter. However, with the iPhone, this lack of WSDL
tooling is becoming a pain in the ass.
Chris, as you yourself said, Cocoa's support for WSDL-based web services is
substantially less than that of .NET... When new developers from the .NET
world start looking at Cocoa and they come across and see that the native
WSDL support is lacking... as someone already mentioned, they might be
inclined to just give up.
As I have said in the past, mac development is mostly desktop-centric. No
one has really cared so far about consuming web services on a mac because
they aren't being used heavily in enterprises. However, the landscape is
definitely changing and web service stuff appears to be coming out of the
IT closet.
http://forums.macrumors.com/showthread.php?t=509880
Well, here is some code for using WSDL from COCOA:
I haven't yet had WSMakeStubs work. Every single WSDL service I've
attempted it on has resulted in a set of ObjC code that doesn't even
compile, let alone work at runtime.