How to call Soap Webservices Synchronously

As I browsed the internet I found a few examples of how to call soap webservices on the iphone. The main example I found actually generated 3 calls – 2 asynchronous and 1 synchronous calls. I then decided a much more concise static method was needed to do the job and while the example I had found works, it isn’t something you would ever want to use in your own application. With that said, here is my solution.

Also to note, If you create a NSURLConnection and don’t use the static sendSynchronousRequest method, you are creating an asynchronous call and should be aware of that.

+ (NSString *)sendSOAPRequest:(NSString *) sRequest :( NSURL *) wsURL :( NSString *) sHeader
{
NSMutableData *myMutableData = [[NSMutableData data] retain];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:wsURL];

[request addValue:@"text/xml; charset:UTF-8" forHTTPHeaderField:@"Content-Type"];
[request addValue:sHeader forHTTPHeaderField:@"SOAPAction"];
NSString *contentLengthStr   = [[NSString alloc] initWithFormat:@”%d”, [sRequest length]];
[request addValue:contentLengthStr forHTTPHeaderField:@"Content-Length"];
[request setHTTPMethod:@"POST"];
[request setHTTPBody:[sRequest dataUsingEncoding:NSUTF8StringEncoding]];

NSError *WSerror;
NSURLResponse *WSresponse;

@try
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
myMutableData = (NSMutableData *)[NSURLConnection sendSynchronousRequest:request
returningResponse:&WSresponse error:&WSerror];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
@catch( NSException* ex )
{
NSLog(@”Webservice Request Failed: Error %@”, [WSerror code]);
}
NSString *theXml = [[NSString alloc]initWithBytes:[myMutableData mutableBytes] length:[myMutableData length] encoding:NSUTF8StringEncoding];
[request release];
[contentLengthStr release];
return [theXml autorelease];
}

Here is a sample Call

+(NSString *) getAuthTokenAndLogin :( NSString *) nsUsername :( NSString *) nsPassword
{
NSString* nsAuthToken = [[NSString alloc] initWithString:@”"];

NSMutableString *sRequest = [[NSMutableString alloc] init];
[sRequest appendString:@"<?xml version=\"1.0\" encoding=\"utf-8\"?>"];
[sRequest appendString:@"<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/\">"];
[sRequest appendString:@"<soap:Body>"];
[sRequest appendString:@"<GetToken xmlns=\"#Service\">"];
[sRequest appendString:@"<RequestXml>"];
[sRequest appendString:@"<Credentials Username=\""];
[sRequest appendString:nsUsername];
[sRequest appendString:@"\" Password=\""];
[sRequest appendString:nsPassword];
[sRequest appendString:@"\"  />"];
[sRequest appendString:@"</RequestXml>"];
[sRequest appendString:@"</GetToken>"];
[sRequest appendString:@"</soap:Body>"];
[sRequest appendString:@"</soap:Envelope>"];

NSURL*      wsURL        = [NSURL URLWithString:@"https://virtualroot.com/service.asmx?op=GetToken"];
NSString*   responseData = [WebServices sendSOAPRequest: sRequest: wsURL :@"#ServiceAggregator/GetToken"];
NSString*   responseXML  = [self getElementValue :responseData :@"ResponseXml>" :@"</ResponseXml" ];
HTMLDecoder*htmldecode   = [[HTMLDecoder alloc] init];
NSString*   xmlData      = [htmldecode convertEntiesInString:responseXML];
NSString*   nsToken      = [self getElementValue :x mlData :@"Token>" :@"</Token" ];
nsAuthToken              = nsToken;
[sRequest release];
return [nsAuthToken autorelease];
}

Hopefully you can make this work for your own webservice, This call will actually fail since the URL doesn’t resolve to anything but this code is from some code I have written previously. I’ll be posting further examples of how I Decode XML using NSXMLParser and how I get substrings as there were topics that were not well documented on the interwebs.