As we discussed in chat, the code in the original question conflates the HTML user interface for testing a web service with the actual web service itself. Your sample code is making a HTTP request of the HTML page that is used for testing the web service. You really probably want to interact directly with your web service.
Having said that, using SOAP/WSDL web service interface makes the process pretty complicated. In the How to access SOAP services from iPhone discussion, I would agree with schwa's conclusion: "don't". More to the point, if you're writing a new web service, some REST service delivering JSON is going to be much easier to work with. Or, if you're stuck with the SOAP-based service, you could write a new web service that consumes the SOAP service and delivers JSON.
If you really want an iOS app to interact directly with the SOAP service defined by a particular WSDL, it seems like there are two approaches: First, you could use one of the source code generators (like sudzc.com). I was underwhelmed by this class of solution out there. Second, you could use a tool like Soap UI to manually create the XML
for a request, and then use that as a template from iOS.
So, I tried out the latter approach:
You mentioned that you followed the tutorial. I actually found this article to be more useful in getting the web service going, but if you had success with the former, that's fine.
I created a web service, HelloTest
, with a Hello
class with a single method, sayHello
, that takes one parameter, the name
, and returns "Hello " + name
:
package com.tutorial;
public class Hello {
public String sayHello(String name){
return "Hello " + name;
}
}
I had Eclipse generate the WSDL for me. The particulars are uninteresting, but it's not entirely dissimilar from yours:
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:ns1="http://org.apache.axis2/xsd" xmlns:ns="http://tutorial.com" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" targetNamespace="http://tutorial.com">
<wsdl:documentation>
Please Type your service description here
</wsdl:documentation>
<wsdl:types>
<xs:schema attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://tutorial.com">
<xs:element name="sayHello">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="name" nillable="true" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="sayHelloResponse">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="return" nillable="true" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
</wsdl:types>
<wsdl:message name="sayHelloRequest">
<wsdl:part name="parameters" element="ns:sayHello"/>
</wsdl:message>
<wsdl:message name="sayHelloResponse">
<wsdl:part name="parameters" element="ns:sayHelloResponse"/>
</wsdl:message>
<wsdl:portType name="HelloPortType">
<wsdl:operation name="sayHello">
<wsdl:input message="ns:sayHelloRequest" wsaw:Action="urn:sayHello"/>
<wsdl:output message="ns:sayHelloResponse" wsaw:Action="urn:sayHelloResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="HelloSoap11Binding" type="ns:HelloPortType">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
<wsdl:operation name="sayHello">
<soap:operation soapAction="urn:sayHello" style="document"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:binding name="HelloSoap12Binding" type="ns:HelloPortType">
<soap12:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
<wsdl:operation name="sayHello">
<soap12:operation soapAction="urn:sayHello" style="document"/>
<wsdl:input>
<soap12:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap12:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:binding name="HelloHttpBinding" type="ns:HelloPortType">
<http:binding verb="POST"/>
<wsdl:operation name="sayHello">
<http:operation location="sayHello"/>
<wsdl:input>
<mime:content type="application/xml" part="parameters"/>
</wsdl:input>
<wsdl:output>
<mime:content type="application/xml" part="parameters"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="Hello">
<wsdl:port name="HelloHttpSoap11Endpoint" binding="ns:HelloSoap11Binding">
<soap:address location="http://localhost:8080/HelloTest/services/Hello.HelloHttpSoap11Endpoint/"/>
</wsdl:port>
<wsdl:port name="HelloHttpSoap12Endpoint" binding="ns:HelloSoap12Binding">
<soap12:address location="http://localhost:8080/HelloTest/services/Hello.HelloHttpSoap12Endpoint/"/>
</wsdl:port>
<wsdl:port name="HelloHttpEndpoint" binding="ns:HelloHttpBinding">
<http:address location="http://localhost:8080/HelloTest/services/Hello.HelloHttpEndpoint/"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
I used Soap UI to take the WSDL and create an example request.
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tut="http://tutorial.com">
<soap:Header/>
<soap:Body>
<tut:sayHello>
<!--Optional:-->
<tut:name>Rob</tut:name>
</tut:sayHello>
</soap:Body>
</soap:Envelope>
It may have been unique to my configuration, but I had to play around with the SOAP envelope generated by Soap UI, replacing the SOAP 1.2 URI:
http://www.w3.org/2003/05/soap-envelope
with a SOAP 1.1 URI:
http://schemas.xmlsoap.org/soap/envelope/
I also, for purposes of example, replaced the ?
placeholder with "Rob" (as I wanted my web service to say hello to me).
Anyway, I now can submit that request in iOS via the following Objective-C code:
NSURL *url = [NSURL URLWithString:@"http://localhost:8080/HelloTest/services/Hello"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
NSString *filename = [[NSBundle mainBundle] pathForResource:@"request1" ofType:@"xml"];
NSData *requestBodyData = [NSData dataWithContentsOfFile:filename];
request.HTTPBody = requestBodyData;
[request setHTTPMethod:@"POST"];
[request addValue:@"http://tutorial.com" forHTTPHeaderField:@"SOAPAction"];
[request addValue:@"text/xml; charset=utf-8" forHTTPHeaderField:@"Content-Type"];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:request
queue:queue
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
NSLog(@"%s", __FUNCTION__);
if (data)
{
NSLog(@"%@", [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding]);
}
}];
Clearly, how you create the NSData
with the request may vary (to keep this "simple" I put the XML of the SOAP request into a text file called request1.xml
and included that in my bundle). Likewise, how you initiate the request may (I used NSURLConnection
method, sendAsynchronousRequest
). But hopefully this gives you an idea of how you'd send a manually created SOAP request.
That generates a response that looks like (I've prettified it, but this is the response):
<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<ns:sayHelloResponse xmlns:ns="http://tutorial.com">
<ns:return>Hello Rob</ns:return>
</ns:sayHelloResponse>
</soapenv:Body>
</soapenv:Envelope>
You can then parse this answer with an XML parser, such as NSXMLParser
.
For me, the "take home" message is that I wouldn't do this unless I absolutely had to. I think that JSON
web services are just as easy to create, and it's far easier to consume their responses in iOS.