Saturday, April 14, 2012

Working with Webservices

In this post we will learn how to use a webservice by sending a SOAP request to the server and reading the output which will be in xml, so in this post I have used the webservice that is provided by w3schools. 

The webservice provided by w3school is used to convert the Celsius temperature into Fahrenheit, the output returned by any webservice can be in json or xml and in this demo the webservice returns an xml structure that will be parsed by using an xml parser
Design Phase:  For the design phase we will make it simple not too much flashy, so here’s a view at the final output.



Design Explanation: The first text field will accept the user input for the temperature that he wants to convert into Fahrenheit and then will display the output in the other text field (Fahrenheit text field).

Step 1: Open Xcode and select the windows based application from the ios template, give this project an appropriate name and then add UIViewController subclass file to this project with the name myView, so now you must be having two new files added into your project that’s myView.h and myView.m, now you can either use interface builder or you can manually code for this view. Get the design ready in the first step just like the above pic and then go to step 2.

Step 2: For making a call to the webservice running in some server you need to call that service via SOAP request, so inorder to know whats the format of your soap request you need to go to the url where your web method is and their you will get the list of appropriate methods that you may want to use so select the appropriate method, below given are the snaps that will help you out for the web method that I am using 

Webservice main page



The SOAP request and response page



Step 3: To execute a web method you need to first need to create the soap body format and pass some of the parameters that are required by that method, and that you can do with the help of the below line


NSString *soapFormat = [NSString stringWithFormat:@"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
"<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/\">\n"
"<soap:Body>\n"
"<CelsiusToFahrenheit xmlns=\"http://tempuri.org/\">\n"
"<Celsius>%@</Celsius>\n"
"</CelsiusToFahrenheit>\n"
"</soap:Body>\n"
"</soap:Envelope>\n",txt1.text];

Next you need to specify the location of the web method and that you can do with the help of the NSURL class


NSURL *locationOfWebService = [NSURLURLWithString:@"http://www.w3schools.com/webservices/tempconvert.asmx"];



Now you need to create a soap header  by using the class NSMutableURLRequest , remember soap body and soap header are two different things, 


NSMutableURLRequest *theRequest = [[NSMutableURLRequestalloc]initWithURL:locationOfWebService];
NSString *msgLength = [NSString stringWithFormat:@"%d",[soapFormat length]];
[theRequest addValue:@"text/xml" forHTTPHeaderField:@"Content-Type"];
[theRequest addValue:@"http://tempuri.org/CelsiusToFahrenheit"forHTTPHeaderField:@"SOAPAction"];
[theRequest addValue:msgLength forHTTPHeaderField:@"Content-Length"];
[theRequest setHTTPMethod:@"POST"];
//the below encoding is used to send data over the net
[theRequest setHTTPBody:[soapFormat dataUsingEncoding:NSUTF8StringEncoding]];


and finally you check whether the connection is established or not with the help of NSURLConnection as it provides support for loading the URL Requests


NSURLConnection *connect = [[NSURLConnection alloc]initWithRequest:theRequest delegate:self];
if (connect) 
{

webData = [[NSMutableData alloc]init];
}
else {
NSLog(@"No Connection established");

}


In the above code I have took a member of NSMutableData and initialized it, this variable will have the entire xml structure that will be required by us to parse, 

The entire code looks like this


-(IBAction)invokeService
{
if ([txt1.text length]==0) {
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"WebService" message:@"Supply Data in text field" delegate:nil cancelButtonTitle:nil otherButtonTitles:@"ok",nil];
[alert show];
[alert release];
}
else {
[txt1 resignFirstResponder];



NSString *soapFormat = [NSString stringWithFormat:@"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
"<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/\">\n"
"<soap:Body>\n"
"<CelsiusToFahrenheit xmlns=\"http://tempuri.org/\">\n"
"<Celsius>%@</Celsius>\n"
"</CelsiusToFahrenheit>\n"
"</soap:Body>\n"
"</soap:Envelope>\n",txt1.text];
NSURL *locationOfWebService = [NSURLURLWithString:@"http://www.w3schools.com/webservices/tempconvert.asmx"];
NSMutableURLRequest *theRequest = [[NSMutableURLRequestalloc]initWithURL:locationOfWebService];
NSString *msgLength = [NSString stringWithFormat:@"%d",[soapFormat length]];
[theRequest addValue:@"text/xml" forHTTPHeaderField:@"Content-Type"];
[theRequest addValue:@"http://tempuri.org/CelsiusToFahrenheit" forHTTPHeaderField:@"SOAPAction"];
[theRequest addValue:msgLength forHTTPHeaderField:@"Content-Length"];
[theRequest setHTTPMethod:@"POST"];
//the below encoding is used to send data over the net
[theRequest setHTTPBody:[soapFormat dataUsingEncoding:NSUTF8StringEncoding]];

NSURLConnection *connect = [[NSURLConnection alloc]initWithRequest:theRequest delegate:self];
if (connect) {
webData = [[NSMutableData alloc]init];
}
else {
NSLog(@"No Connection established");
}
}
}



Step 4: The NSURLConnection class has delegate method that we must implement so that we can read the xml structure that is returned by the webservice, if you want to see the xml format of the webservice that is returned then it will be provided just below the soap request section.

The delegate methods of NSURLConnection that you will be using are 

didReceiveResponse: In this method you set the mutabledata’s length to zero so that the data present from any previous request is clear

didReceiveData: Append the mutabledata variable with the data received from the webservice

didFailWithError: If the internet connection crashes then write code inside this method to prompt a message to the user for connection failure.

connectionDidFinishLoading: You will be writing code inside this method once the loading of the xml output is done in the mutable data

So heres how the entire code looks


//NSURLConnection delegate method

-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[webData setLength0];
}

-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[webData appendData:data];
}

-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(@"ERROR with theConenction");
[connection release];
[webData release];
}

-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(@"DONE. Received Bytes: %d", [webData length]);
xmlParser = [[NSXMLParser alloc]initWithData:webData];
[xmlParser setDelegateself];
[xmlParser parse];
[connection release];
}



Step 5: Now its time to parse the xml for this I haven’t used GData Parser I have used the NSXMLParser to parse the xml, so from step 4 you can see I have allocated and initialized memory space for the parser and it has some delegate method that I have used to get the work done


- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
[nodeContent appendString:[string stringByTrimmingCharactersInSet:[NSCharacterSetwhitespaceAndNewlineCharacterSet]]];
}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:@"CelsiusToFahrenheitResult"]) {
finaldata = nodeContent;
output.text = finaldata;
}
output.text = finaldata;
}


You may use any xml parser of your choice

Now go to the appDelegate.m file and add the view to your window


#import "webserviceDemoAppDelegate.h"
#import "myView.h"

@implementation webserviceDemoAppDelegate

@synthesize window;
#pragma mark -
#pragma mark Application lifecycle

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {    
    
    // Override point for customization after application launch.
    
myView *obj = [[myView alloc]initWithNibName:@"myView" bundle:nil];
[window addSubview:obj.view];
    [self.window makeKeyAndVisible];
    
    return YES;
}


press build and go to run the application, here's a view at the final output






You may download the source code from this link.

No comments:

Post a Comment