Consuming a SOAP Web Service within an iOS app

In this tutorial we will look at how to consume a SOAP Web service from within an iOS application. I will be using a .NET based web service for this tutorial. Since the mode of communication between both the platforms will be SOAP XML, the same example I believe will hold good for any SOAP XML Web service.

Let us the consider a simple web method which takes two string parameters and returns a string. Just to keep things simple, this web method doesn’t do any work, as discussed above, just accepts two string parameters and returns a string. The SOAP request for the web method looks something like this,

POST /Test.asmx HTTP/1.1
Host: psmdpublic
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://tempuri.org/iOSTutorial"

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <iOSTutorial xmlns="http://tempuri.org/">
      <input1>string</input1>
      <input2>string</input2>
    </iOSTutorial>
  </soap:Body>
</soap:Envelope>

If we look at the above XML SOAP request, “input1” and “input2” are the two string inputs the web method takes. On the other hand, the response for the request looks something like this,

HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <iOSTutorialResponse xmlns="http://tempuri.org/">
      <iOSTutorialResult>string</iOSTutorialResult>
    </iOSTutorialResponse>
  </soap:Body>
</soap:Envelope>

The string in the nodes “iOSTutorialResult” is the response string

We will now look at at how to initiate an asynchronous “NSURLConnection” request to connect to the web service along with supplying the parameters. Before we go any further, make sure you have imported the “NSURLConnectionDelegate” and “NSXMLParserDelegate” into the header file like I have done below

@interface ModuleListController : UITableViewController<NSURLConnectionDelegate,NSXMLParserDelegate>

Once that is done, in the implementation part, we instantiate “NSURLConnection” asynchronously to request to the web service. This can be ideally done in “ViewDidLoad” method, though depending on the requirement, you might also want to call this piece of code from with any method. Eg. On click of a button. I used this code to connect to a web service and populate a “UITableViewController”, though I have not included the code to populate tableview as it is an easy one to find on the web.

    NSString *urlString = @"http://[URL]/[web_service_name.asmx]/[web_method]";
    NSURL *url = [NSURL URLWithString:urlString];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [request setHTTPMethod: @"POST"];

    //Setting parameters section Begin

    NSString *myRequestString1 = @"input1"; // Attention HERE!!!!
    NSString *myParamString1=@"input1_value";

    NSString *myRequestString2 = @"input2"; // Attention HERE!!!!
    NSString *myParamString2=@"input2_value";

    NSString *reqStringFUll=[NSString stringWithFormat:@"%@=%@&%@=%@",myRequestString1,myParamString1,myRequestString2,myParamString2];
    NSData *requestData = [NSData dataWithBytes:[reqStringFUll UTF8String] length:[reqStringFUll length]];
    [request setHTTPBody: requestData];

    //Setting parameters section ends

    NSURLConnection _conn=[[NSURLConnection alloc]initWithRequest:request delegate:self ];

Substitute the URL, name of the web service and the name of the web method in the placeholders. After instantiating “NSMutableURLRequest” and setting parameters, instantiate an “NSURLConnection” object and start the request setting the delegate to self. This will automatically call the “NSURLConnection” life cycle delegate methods.

Declare the following two variables at the top of the implementation file (.m) file after synthesising properties if any.

NSMutableData *_responseData;
NSMutableString *currentElement; 
#pragma mark NSURLConnection Delegate Methods

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    // A response has been received, this is where we initialize the instance var you created
    // so that we can append data to it in the didReceiveData method
    // Furthermore, this method is called each time there is a redirect so reinitializing it
    // also serves to clear it
    _responseData = [[NSMutableData alloc] init];

}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    // Append the new data to the instance variable you declared
    [_responseData appendData:data];
}

- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
                  willCacheResponse:(NSCachedURLResponse*)cachedResponse {
    // Return nil to indicate not necessary to store a cached response for this connection
    return nil;
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    // The request is complete and data has been received
    // You can parse the stuff in your instance variable now

    NSXMLParser *parser=[[NSXMLParser alloc] initWithData:_responseData];
    [parser setDelegate:self];
    [parser parse];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    // The request has failed for some reason!
    // Check the error var
    NSLog(@"Error : %@",[error localizedDescription]);
}

Once the request starts receiving data, the data gets appended to the “NSMutableData” object we create earlier. Once the request is finished, an “NSXMLParser” object is instantiated with the “_responseData” and in-turn, the “NSXMLParser” life cycle delegate methods gets called automatically. The SOAP XML response for the request looks like this,

<string xmlns="http://tempuri.org/">result</string>

- (void)parserDidStartDocument:(NSXMLParser *)parser
 {
 NSLog(@"Parser start");
 }
- (void) parser: (NSXMLParser *) parser didStartElement: (NSString *) elementName
 namespaceURI: (NSString *) namespaceURI qualifiedName: (NSString *) qName attributes: (NSDictionary *) attributeDict
 {
     if ([elementName isEqualToString:@"string"])
     {
         currentElement = [[NSMutableString alloc] init];
         return;
     }
 }
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
 {
     [currentElement appendString:string];
 }
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
 {
 if([elementName isEqualToString:@"string"])
 {
     return;
 }
 }
- (void)parserDidEndDocument:(NSXMLParser *)parser
 {
 }

That is all we have to do. The xml parser, parses every node with name “string” and fetches the value and appends that to the “NSMutableString” object named “currentElement”. Once the parser finishes, the control reaches “parserDidEndDocument”. I had this piece of code in a “UITableViewController” and I added every value fetched from parsing the XML response into an “NSMutableArray” from which I populated the table

Advertisements

5 thoughts on “Consuming a SOAP Web Service within an iOS app

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s