• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 3315
  • Last Modified:

ASP.net webservices in IOS - how to

Hi, we’ve got a load of asp.net webservices that are running fine and provide data from our in house system.

We want to use these webservices on a native IPhone/Ipad app built using XCode and IOS 5.

I’ve been looking into how to consume the asp.net webservices on IOS and haven’t really found anything definitive, even putting in “IOS webservices” in amazon only returns 2 possible books….so I came back to EE and found this:

http://www.experts-exchange.com/Apple/Programming/iOS/Q_26781639.html

but the link from that page no longer works.

I understand that IOS doesn’t have inbuilt framework for working with SOAP, so you have to do it yourself.

So, what do people do in the real world? this is for a business app pulling data from our own system to a remote deice in one of our engineers hands.

As we’re a .net company, we’re obviously more at home with webservices, but what is the BEST solution for getting data to an IOS application from a remote server?
One article said that using an asp.net page with querystring parameters, outputting XML or JSON straight into the page response and reading that…. but that doesn’t sound a very “modern” solution.

Thanks in advance.
1
PatrickK_W
Asked:
PatrickK_W
  • 2
1 Solution
 
Hamidreza VakilianSenior iOS DeveloperCommented:
Consuming a web service in iOS is much easier if you look this way:
1- You have to create a request and send it to server (Obviously you have to conform to soap XML syntax)
2- You will receive the response. The response will be in XML format so you have to parse it to get access to the data; hence you will use NSXMLParser or something else if you prefer.
3- Parse and access the data.

You can find useful resources here:
http://stackoverflow.com/questions/204465/how-to-access-soap-services-from-iphone
Raywenderlich tutorial which uses ASI library to consume web service:
http://www.raywenderlich.com/2965/how-to-write-an-ios-app-that-uses-a-web-service

2 years ago I wrote a class for my project which did the SOAP stuff for me (the web service was .asmx asp.net); I have attached it for you. Check .h file for usage -- You may customize it for your own use -- It may contain bugs since I did not spent much time for it.

Actually the best solution for transferring data between a client and server depends on your project. If you need to have a consistent data transfer or the device has to connect to server frequently it's probably much better to implement socket connection between the two. If you plan to use socket connection approach you will have get extra benefits over the web service approach:
- Parsing the data using sockets will be much easier on client side since you can define your own custom protocol
- You transfer speed will be much higher using sockets
- You have a big latency when you send a XML request since it's connectionless but in sockets you will have somehow a more uptime data transfer

But you should notice, a server/client system which is based on web services is much more easier to implement; It's much easier to debug; It's more portable, you can integrate the web services easier in other platforms.


SOAP.h:
//
//  soap.h
//  splitview
//
//  Created by Hamidreza Vakilian on 8/11/11.
//  Copyright 2011 H.Vakilian. All rights reserved.
//
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= Usage:
//    SEL theSelector = @selector(mysoalcallback:);///Setting NSInvocation for the callback function to be called then
//    NSMethodSignature *theSignature = [self methodSignatureForSelector:theSelector];
//    NSInvocation *anInvocation = [NSInvocation invocationWithMethodSignature:theSignature];
//    [anInvocation setSelector:theSelector];
//    [anInvocation setTarget:self];
//
//
//    soap *s = [[soap alloc] initWithWebServiceURL:@"http://192.168.1.50/ipadtest/service1.asmx"];
//    //you may use init but with the default URL set up in soap.m
//    [s executeWebMethod:@"test" :nil :anInvocation];//calling the webmethod
//
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= Call Back Function:
//    -(void)mysoalcallback:(NSArray*) result
//    {
//        if(!result)
//            NSLog(@"No Result!");///occurs for void webmethods
//            else
//            ////web method with results in result, do your job here
//    }
//
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=



#import <Foundation/Foundation.h>

@interface soap: NSObject <NSXMLParserDelegate> 
{
    
    NSMutableData *webData;
	NSMutableString *soapResults;
	NSXMLParser *xmlParser;
	BOOL recordResults;
    
    NSInvocation *callbackfunction;
    NSString *_methodName;
    NSArray *_methodArguments;
    NSMutableArray *methodResultValues;
    NSMutableArray *methodResultNames;
    NSString* lastelement;
    NSString* parsed_chars;
    
    NSMutableString *webserviceurl;
}

-(void) executeWebMethod:(NSString*)methodName:(NSArray*)methodArguments:(NSInvocation*)callback;
@property (retain, nonatomic) NSString *_methodName;
@property (retain, nonatomic) NSArray *_methodArguments;
@property (retain, nonatomic) NSMutableString *webserviceurl;

-(id)initWithWebServiceURL:(NSString*) url;
@end

Open in new window


SOAP.m:
//
//  soap.m
//  splitview
//
//  Created by Hamidreza Vakilian on 8/11/11.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import "soap.h"

@implementation soap

@synthesize _methodName, _methodArguments, webserviceurl;


- (id)init
{
    self = [super init];
    if (self) {
        // Initialization code here.
        
        ////default webservice loacation for this project
        ////if you want to set another url use initWithWebServiceURL
        webserviceurl = [[NSMutableString alloc] initWithString:@"http://192.168.1.50/ipadtest/service1.asmx"];
        
        
    }
    
    return self;
}

-(NSString*) createArgumentsTags:(NSArray*)arguments
{
    NSString *result = @"";
    
    if(arguments)
    for (int i = 0; i != [arguments count] ; i+=2) {
        result = [NSString stringWithFormat:
                  @"%@"
                  "<%@>"
                  "%@"
                  "</%@>\n"
                  ,result, [arguments objectAtIndex:i], [arguments objectAtIndex:i+1], [arguments objectAtIndex:i] ];
    }
    
    return  result;
    
}


-(void) executeWebMethod:(NSString*)methodName:(NSArray*)methodArguments:(NSInvocation*)callback
        //This function executes the desired method from the corresponding webservice
        //      methodName: name of the method on the web service to call
        //      methodArguments: arguments of the method with this syntax:
        //                          arg1Name, arg1Value, arg2Name, arg2Value,...
        //      callback: the NSInvocation of the callback function that will be called when the method execution ends
{
    	recordResults = FALSE;
    
    callbackfunction = callback;
    
    methodResultValues = [[NSMutableArray alloc] init];
    methodResultNames = [[NSMutableArray alloc] init];
    lastelement = [[NSString alloc] init];
    parsed_chars = [[NSString alloc] init];
    
    self._methodName = methodName;
    self._methodArguments = methodArguments;
    
    
    NSString *soapMessage = [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"
							 "<%@ xmlns=\"http://tempuri.org/\">\n"
                             "%@"
                             "</%@>\n"
							 "</soap:Body>\n"
							 "</soap:Envelope>\n", methodName, [self createArgumentsTags:methodArguments],methodName
							 ];
	NSLog(soapMessage,"");
	
	NSURL *url = [NSURL URLWithString:self.webserviceurl];//@"http://192.168.1.50/ipadtest/service1.asmx"
	NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:url];
	NSString *msgLength = [NSString stringWithFormat:@"%d", [soapMessage length]];
	
	[theRequest addValue: @"text/xml; charset=utf-8" forHTTPHeaderField:@"Content-Type"];
	[theRequest addValue:[NSString stringWithFormat: @"http://tempuri.org/%@", methodName] forHTTPHeaderField:@"SOAPAction"];
	[theRequest addValue: msgLength forHTTPHeaderField:@"Content-Length"];
	[theRequest setHTTPMethod:@"POST"];
	[theRequest setHTTPBody: [soapMessage dataUsingEncoding:NSUTF8StringEncoding]];
	
	NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
	
	if( theConnection )
	{
		webData = [NSMutableData data];
	}
	else
	{
		NSLog(@"soap.m: theConnection is NULL");
	}
	   
}

-(id)initWithWebServiceURL:(NSString*) url
{
    webserviceurl = [[NSMutableString alloc] initWithString:url];
    return  self;
}


-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
	[webData setLength: 0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
	[webData appendData:data];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
	NSLog(@"soap.m: ERROR with theConenction");
    
    if (callbackfunction) {
            [callbackfunction invoke];
    }

}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
	NSLog(@"soap.m: DONE. Received Bytes: %d", [webData length]);
	NSString *theXML = [[NSString alloc] initWithBytes: [webData mutableBytes] length:[webData length] encoding:NSUTF8StringEncoding];
	NSLog(theXML,"");
	
	xmlParser = [[NSXMLParser alloc] initWithData: webData];
	[xmlParser setDelegate: self];
	[xmlParser setShouldResolveExternalEntities: YES];
	[xmlParser parse];
}

-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *) namespaceURI qualifiedName:(NSString *)qName
   attributes: (NSDictionary *)attributeDict
{
    parsed_chars = nil;
    lastelement = elementName;
    
	if( [elementName isEqualToString:[NSString stringWithFormat: @"%@Result", self._methodName]])
	{
		recordResults = TRUE;
	}

}
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
	if( recordResults )
	{
        parsed_chars = string;
	}
}



-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
    if( [elementName isEqualToString:lastelement] )
    {
        if (parsed_chars) 
        [methodResultValues addObject: parsed_chars];
        else
        [methodResultValues addObject: @""];            
        
        [methodResultNames addObject:lastelement];
        
    }
    
	if( [elementName isEqualToString:[NSString stringWithFormat: @"%@Result", self._methodName]])
	{
		recordResults = FALSE;
	
        if(callbackfunction)
        {
        [callbackfunction setArgument:&methodResultValues atIndex:2];
        [callbackfunction setArgument:&methodResultNames atIndex:3];
        [callbackfunction invoke];
        }
	}
}

@end

Open in new window

0
 
PatrickK_WAuthor Commented:
That’s great thanks.
The data is coming from a large SQL Server DB. The general idea is that the user gets their list of jobs daily, then updates the details of what they did on the iphone, then uploads the completion data back to the database.

Of course that’s the simple outline – there are a lot of tables and data required to do this. the job itself is made up of multiple tables, and there are other entities, such as parts used, time spent, etc that is collected for the job.

The data structure is quite complicated. Another question – and I’ll open another thread for this is – is it best to replicate the DB schema in SQLLite or “flatten” the strucuter as much as possible for SQLLite.
0
 
PatrickK_WAuthor Commented:
thanks for that. on the same idea, i've asked another question on a slightly different topic:
http://www.experts-exchange.com/Apple/Programming/iOS/Q_27847727.html

about structuring complex data structures in SQLLite

thanks
0

Featured Post

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now