Advertise here




Advertise here

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Resolved: How to Call a SOAP Service

TrilitechTrilitech Posts: 28Registered Users
edited May 2011 in iPhone SDK Development
Like many others I wrote an app that was heavily dependent on asp.net SOAP web services that worked great in the simulator and then got hit with the surprise that the CoreServices library that contained all the web service functionality wasn't actually available on the iPhone. I'm still holding out hope this functionality will be added eventually.

All my code was dependant on receiving back the NSDictionary and NSArray object tree, and I didn't want to rewrite it all, so I created a wrapper to emulate the missing SOAP functionality by passing the request over REST. This allowed me to just swap out the method I was using for the webservice calls and keep the rest of the code the same. I thought I'd share it for anyone else in the same boat.

Fortunately asp.net already supports REST style requests (I didn't realize this before today), so no changes were needed on the web server side.

To demonstrate here the call to a simple method called "SayHello". You pass in name and it returns a single item called "string" that contains "Hello [yourname]". The code will work with more complex objects with child properties as well, and return them as NSDictionary and NSArray objects, but for simplicity I'm using "SayHello".
NSArray *keys = [NSArray arrayWithObjects:@"userName", nil];
NSArray *objects = [NSArray arrayWithObjects:@"jeremy", nil];
NSDictionary *params = [NSDictionary dictionaryWithObjects:objects forKeys:keys];
NSDictionary *wsResponse=[WebServices callRestService:@"SayHello" :params];

NSString *responseString=[wsResponse objectForKey:@"string"];

callRestService is a helper method I created in a class called Webservices. This code was exactly the same before except the helper method was called callSoapService.

WebServices.m contains two methods. getRestUrl just appends all the method parameters into a url to make the REST request. callRestService uses the build-in NSXMLParser class to retrieve the xml and sends it to a custom class called XmlParser to handle the callbacks and create the NSDictionary result,

WebServices.m
+(id)callRestService: (NSString *) methodName : (NSDictionary *) params
{
	NSURL *url=[WebServices getRestUrl: methodName : params];
	XmlParser *xmlParser = [[XmlParser alloc] init];
	
	NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
	[parser setDelegate:xmlParser];
	[parser setShouldProcessNamespaces:NO];
	[parser setShouldReportNamespacePrefixes:NO];
	[parser setShouldResolveExternalEntities:NO];
	[parser parse];
	[parser release];
	return xmlParser.result;
}

+(NSURL *)getRestUrl: (NSString *) methodName : (NSDictionary *) params
{
	NSString *url=@"http://services.mywebsite.com/mywebservice.asmx/";
	url=[url stringByAppendingString:methodName];
	
	BOOL firstKey=TRUE;
	for (NSString *key in params)
	{
		NSString *value=[params objectForKey:key];
		if (firstKey) url=[url stringByAppendingString:@"?"]; else url=[url stringByAppendingString:@"&"];
		url=[url stringByAppendingString:key];
		url=[url stringByAppendingString:@"="];
		url=[url stringByAppendingString:value];
		firstKey=FALSE;
	}
	return [NSURL URLWithString:url];
}


The final step is to create the XmlParser handler. This class keeps track of each open and close tag to build an object tree containing NSMutableArray NSMutableDictionary and NSString objects.

XmlParser.h
#import <Foundation/Foundation.h>


@interface XmlParser : NSObject {
	NSMutableDictionary *result;
	NSString *currentElementName;
	NSString *currentElementValue;
	NSMutableArray *parentArray;
}

@property (nonatomic, retain) NSMutableDictionary *result;
@property (nonatomic, retain) NSString *currentElementName;
@property (nonatomic, retain) NSString *currentElementValue;
@property (nonatomic, retain) NSMutableArray *parentArray;


- (void)parserDidStartDocument:(NSXMLParser *)parser;
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict;
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName;
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string;

@end


XmlParser.m
#import "XmlParser.h"


@implementation XmlParser
@synthesize result;
@synthesize currentElementName;
@synthesize currentElementValue;
@synthesize parentArray;


- (void)parserDidStartDocument:(NSXMLParser *)parser
{
	result=[[NSMutableDictionary alloc] init];
	parentArray=[[NSMutableArray alloc] init];
	[parentArray addObject:result];
	currentElementName=@"";
}

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
	if (qName) {
		elementName = qName;
	}
	currentElementValue=@"";
	if (currentElementName!=@"")
	{
		id newParent=NULL;
		if ([currentElementName isLike:@"*Array*"])
		{
			newParent=[[NSMutableArray alloc] init];
		} else {
			newParent=[[NSMutableDictionary alloc] init];
		}
		[parentArray addObject:newParent];
	}
	currentElementName=elementName;
}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{     
	if (qName) {
		elementName = qName;
	}
	
	if (currentElementName==@"")
	{
		//We're adding a container with children.  Add it to the parent and remove this item fromt he parentArray
		int currentIndex=[parentArray count]-1;
		int parentIndex=currentIndex - 1;
		id currentChild=[parentArray objectAtIndex:currentIndex];
		id currentParent=[parentArray objectAtIndex:parentIndex];
		
		if ([currentParent isKindOfClass:[NSMutableArray class]])
		{
			[currentParent addObject:currentChild];
		} else {
			[currentParent setObject:currentChild forKey:elementName];
		}
		
		[parentArray removeObjectAtIndex:currentIndex];
	} else {
		//We're adding a simple type element
		int currentIndex=[parentArray count]-1;
		id currentParent=[parentArray objectAtIndex:currentIndex];
		if ([currentParent isKindOfClass:[NSMutableArray class]])
		{
			[currentParent addObject:currentElementValue];
		} else {
			[currentParent setObject:currentElementValue forKey:currentElementName];
		}
	}
	currentElementName=@"";
}


- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
	currentElementValue=string;
}

@end


That's it. I'm sure it's not the cleanest code (This is my very first XCode app) and there may be a better way of doing this, but it saved me from having to rewrite all my code that was retrieving data from SOAP services. I've seen tons of other people with the same problem and no solutions so far. I hope this helps.
Post edited by Trilitech on
«134

Replies

  • maverick808maverick808 Posts: 5New Users
    edited August 2008
    You've posted the xmlparser interface twice, missing out the implementation for it. Could you fix that please?
  • TrilitechTrilitech Posts: 28Registered Users
    edited August 2008
  • pashikpashik Posts: 75Registered Users
    edited August 2008
    Trilitech wrote: »
    Sorry about that. I updated it.

    thanx a lot.

    It would be great if u create zip with file classes and attach to ur message.
  • realberenrealberen Posts: 60Registered Users
    edited August 2008
    Thanks for the post. Just wondering, if you're interacting more, like sending data like you would normally do in the SOAP envelope, how do you do that in this scenario?

    Cheers

    Nik
  • wtyphoonwtyphoon Posts: 2New Users
    edited August 2008
    I too am keen to see how things go with more data going back and forth, before I decide on this route vs plain XML and manual parsing.

    One thing I'm going to need to resolve is binary (base64) going back and forth as well at some point. Judging by the apparent lack of .NET <> Cocoa SOAP success, I may well be in for an uphill struggle.

    Thanks for posting so far.
  • TrilitechTrilitech Posts: 28Registered Users
    edited August 2008
    realberen - Currently it doesn't handle sending complex objects as part of the message, it can just receive them. (that's all I needed for my app, so I didn't take it that far). The REST handling is built in on the ASP.NET side, so if you can figure out the parameter names it expects for these complex objects, I don't see any reason why you couldn't create a generic method to convert your XCode objects into those parameters.

    wtyphoon - Definitely no base 64 support either. Although you should receive the string value back and be able to decode it in the XCode.

    As far as whether it's better to take this approach or just call rest and handle it manually for each web service call, it was a no-brainer for me. It's a royal pain to deal with three different methods to receive the open tag, close tag and contents, and keep track of all your nesting to and build out your object tree. The missing "built-in" classes provide you with a nice object tree instead of the series of methods which is FAR easier to convert into your custom objects. That's what I set out to replicate here.

    I'm still absolutely shocked Apple would leave this core functionality on a platform made for developing web connected mobile apps. I'm still holding out hope this will eventually be added. In theory, once it is, I can just swap out this code for the built-in libraries without having to change all my code that converts the result into my custom objects.
  • varcharvarchar NYCPosts: 138Registered Users @ @
    edited September 2008
    This code is great... helped me out with a core app I am doing.

    I hope you do not mind, I used your code and created 2 generic methods:


    /* url - string url of web service (including .asmx) methodName - string methodname(operation) of webservice keys = parameters of web service objects = values of each parameter in web service example: NSArray *keys = [NSArray arrayWithObjects:@"USZip", nil]; NSArray *keyvalues = [NSArray arrayWithObjects:@"11235", nil]; [self generateWebServiceURLRequest: @"http://www.mywebsite.com/mywebservice.asmx"; : @"getMyData": keys: keyvalues] */ +(NSURLRequest *) generateWebServiceURLRequest : (NSString *) url: (NSString *) methodName: (NSArray *) keys: (NSArray *) objects { NSDictionary *params = [NSDictionary dictionaryWithObjects:objects forKeys:keys]; NSString *newMethodName; // We need to start the methodName with a / - since we are using GET Request method newMethodName = @"/"; newMethodName = [newMethodName stringByAppendingString: methodName]; url=[url stringByAppendingString:newMethodName]; BOOL firstKey=TRUE; for (NSString *key in params) { NSString *value=[params objectForKey:key]; if (firstKey) url=[url stringByAppendingString:@"?"]; else url=[url stringByAppendingString:@"&"]; url=[url stringByAppendingString:key]; url=[url stringByAppendingString:@"="]; url=[url stringByAppendingString:value]; firstKey=FALSE; } NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0]; return theRequest; } +(NSURL *) generateWebServiceHTTPGetURL : (NSString *) url: (NSString *) methodName: (NSArray *) keys: (NSArray *) objects { NSDictionary *params = [NSDictionary dictionaryWithObjects:objects forKeys:keys]; NSString *newMethodName; NSURL *resultURL; // We need to start the methodName with a / - since we are using GET Request method newMethodName = @"/"; newMethodName = [newMethodName stringByAppendingString: methodName]; NSLog(@"generateWebServiceHTTPGetURL: newMethodName: %@",newMethodName); url=[url stringByAppendingString:newMethodName]; BOOL firstKey=TRUE; for (NSString *key in params) { NSString *value=[params objectForKey:key]; if (firstKey) url=[url stringByAppendingString:@"?"]; else url=[url stringByAppendingString:@"&"]; url=[url stringByAppendingString:key]; url=[url stringByAppendingString:@"="]; url=[url stringByAppendingString:value]; firstKey=FALSE; } NSLog(@"generateWebServiceHTTPGetURL: URL: %@",(NSString *)url); resultURL = [NSURL URLWithString:url]; return resultURL; } [/Code][Code]

    /*
    url - string url of web service (including .asmx)
    methodName - string methodname(operation) of webservice
    keys = parameters of web service
    objects = values of each parameter in web service

    example:


    NSArray *keys = [NSArray arrayWithObjects:@"USZip", nil];
    NSArray *keyvalues = [NSArray arrayWithObjects:@"11235", nil];


    [self generateWebServiceURLRequest: @"http://www.mywebsite.com/mywebservice.asmx" : @"getMyData": keys: keyvalues]

    */
    +(NSURLRequest *) generateWebServiceURLRequest : (NSString *) url: (NSString *) methodName: (NSArray *) keys: (NSArray *) objects
    {
    NSDictionary *params = [NSDictionary dictionaryWithObjects:objects forKeys:keys];

    NSString *newMethodName;

    // We need to start the methodName with a / - since we are using GET Request method
    newMethodName = @"/";
    newMethodName = [newMethodName stringByAppendingString: methodName];

    url=[url stringByAppendingString:newMethodName];

    BOOL firstKey=TRUE;
    for (NSString *key in params)
    {
    NSString *value=[params objectForKey:key];
    if (firstKey) url=; else url=;
    url=
    ;
    url=
    ;
    url=
    [url stringByAppendingString:value];
    firstKey=FALSE;
    }

    NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:url]
    cachePolicy:NSURLRequestUseProtocolCachePolicy
    timeoutInterval:60.0];

    return theRequest;
    }


    +(NSURL *) generateWebServiceHTTPGetURL : (NSString *) url: (NSString *) methodName: (NSArray *) keys: (NSArray *) objects
    {
    NSDictionary *params = [NSDictionary dictionaryWithObjects:objects forKeys:keys];

    NSString *newMethodName;

    NSURL *resultURL;

    // We need to start the methodName with a / - since we are using GET Request method
    newMethodName = @"/";
    newMethodName = [newMethodName stringByAppendingString: methodName];

    NSLog(@"generateWebServiceHTTPGetURL: newMethodName: %@",newMethodName);

    url=[url stringByAppendingString:newMethodName];

    BOOL firstKey=TRUE;
    for (NSString *key in params)
    {
    NSString *value=[params objectForKey:key];
    if (firstKey) url=; else url=;
    url=
    ;
    url=
    ;
    url=
    [url stringByAppendingString:value];
    firstKey=FALSE;
    }

    NSLog(@"generateWebServiceHTTPGetURL: URL: %@",(NSString *)url);

    resultURL = [NSURL URLWithString:url];

    return resultURL;
    }

    [/Code]
  • blackyEblackyE GermanyPosts: 87Registered Users @
    edited September 2008
    hello,


    is it possible to connect that to a button?
    where you have entered in a textviel your username and password?

    can you plz describe me how can i do that....:(


    thanks,
    blackyE
  • varcharvarchar NYCPosts: 138Registered Users @ @
    edited September 2008
    Yes.


    Just create button via Interface Builder.
    Create the IBOutlet and IBAction.
    Then have IBAction method call the WS and use the UITextfield value property for the textfield data.
  • blackyEblackyE GermanyPosts: 87Registered Users @
    edited September 2008
  • varcharvarchar NYCPosts: 138Registered Users @ @
    edited September 2008
    See below for all the code:

    WebServiceHelper.h

    #import <UIKit/UIKit.h> @interface WebServiceHelper : NSObject { } +(NSURLRequest *) generateWebServiceURLRequest : (NSString *) url: (NSString *) methodName: (NSArray *) keys: (NSArray *) objects; +(NSURL *) generateWebServiceHTTPGetURL : (NSString *) url: (NSString *) methodName: (NSArray *) keys: (NSArray *) objects; @end [/Code] WebServiceHelper.m [Code] #import "WebServiceHelper.h" @implementation WebServiceHelper /* url - string url of web service (including .asmx) methodName - string methodname(operation) of webservice keys = parameters of web service objects = values of each parameter in web service example: NSArray *keys = [NSArray arrayWithObjects:@"USZip", nil]; NSArray *keyvalues = [NSArray arrayWithObjects:@"11235", nil]; [self generateWebServiceURLRequest: @"http://www.mywebsite.com/mywebservice.asmx"; : @"getMyData": keys: keyvalues] */ +(NSURLRequest *) generateWebServiceURLRequest : (NSString *) url: (NSString *) methodName: (NSArray *) keys: (NSArray *) objects { NSDictionary *params = [NSDictionary dictionaryWithObjects:objects forKeys:keys]; NSString *newMethodName; // We need to start the methodName with a / - since we are using GET Request method newMethodName = @"/"; newMethodName = [newMethodName stringByAppendingString: methodName]; url=[url stringByAppendingString:newMethodName]; BOOL firstKey=TRUE; for (NSString *key in params) { NSString *value=[params objectForKey:key]; if (firstKey) url=[url stringByAppendingString:@"?"]; else url=[url stringByAppendingString:@"&"]; url=[url stringByAppendingString:key]; url=[url stringByAppendingString:@"="]; url=[url stringByAppendingString:value]; firstKey=FALSE; } NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0]; return theRequest; } +(NSURL *) generateWebServiceHTTPGetURL : (NSString *) url: (NSString *) methodName: (NSArray *) keys: (NSArray *) objects { NSDictionary *params = [NSDictionary dictionaryWithObjects:objects forKeys:keys]; NSString *newMethodName; NSURL *resultURL; // We need to start the methodName with a / - since we are using GET Request method newMethodName = @"/"; newMethodName = [newMethodName stringByAppendingString: methodName]; NSLog(@"generateWebServiceHTTPGetURL: newMethodName: %@",newMethodName); url=[url stringByAppendingString:newMethodName]; BOOL firstKey=TRUE; for (NSString *key in params) { NSString *value=[params objectForKey:key]; if (firstKey) url=[url stringByAppendingString:@"?"]; else url=[url stringByAppendingString:@"&"]; url=[url stringByAppendingString:key]; url=[url stringByAppendingString:@"="]; url=[url stringByAppendingString:value]; firstKey=FALSE; } NSLog(@"generateWebServiceHTTPGetURL: URL: %@",(NSString *)url); resultURL = [NSURL URLWithString:url]; return resultURL; } @end [/Code] MyViewController.h (obviously any view controller) [Code] #import <UIKit/UIKit.h> @interface MyViewController : UIViewController { IBOutlet UILabel *lblUserName; IBOutlet UILabel *lblPW; } @property (nonatomic, retain) UILabel *lblUserName; @property (nonatomic, retain) UILabel *lblPW; -(IBAction) callMyWebService: (id) sender; @end [/Code] MyViewController.m [Code] #import "myViewController.h" @implementation myViewController @synthesize lblUserName, lblPW; -(IBAction) callMyWebService: (id) sender { NSURL *theURL; NSArray *keys = [NSArray arrayWithObjects:@"userName",@"passWord", nil]; NSArray *keyvalues = [NSArray arrayWithObjects:lblUserName.text,lblPW.text, nil]; theURL = [WebServiceHelper generateWebServiceHTTPGetURL: @"http://www.mywebsite.com/mywebservice.asmx": @"mywebservicemethod": keys: keyvalues]; // The rest of the code you will have to use NSXMLParser to parse the WS XML } [/Code] I hope the above will help you... maybe some syntax errors... wrote it by hand.... Good luck....[Code]

    #import <UIKit/UIKit.h>


    @interface WebServiceHelper : NSObject {


    }

    +(NSURLRequest *) generateWebServiceURLRequest : (NSString *) url: (NSString *) methodName: (NSArray *) keys: (NSArray *) objects;
    +(NSURL *) generateWebServiceHTTPGetURL : (NSString *) url: (NSString *) methodName: (NSArray *) keys: (NSArray *) objects;

    @end


    [/Code]


    WebServiceHelper.m

    #import "WebServiceHelper.h" @implementation WebServiceHelper /* url - string url of web service (including .asmx) methodName - string methodname(operation) of webservice keys = parameters of web service objects = values of each parameter in web service example: NSArray *keys = [NSArray arrayWithObjects:@"USZip", nil]; NSArray *keyvalues = [NSArray arrayWithObjects:@"11235", nil]; [self generateWebServiceURLRequest: @"http://www.mywebsite.com/mywebservice.asmx"; : @"getMyData": keys: keyvalues] */ +(NSURLRequest *) generateWebServiceURLRequest : (NSString *) url: (NSString *) methodName: (NSArray *) keys: (NSArray *) objects { NSDictionary *params = [NSDictionary dictionaryWithObjects:objects forKeys:keys]; NSString *newMethodName; // We need to start the methodName with a / - since we are using GET Request method newMethodName = @"/"; newMethodName = [newMethodName stringByAppendingString: methodName]; url=[url stringByAppendingString:newMethodName]; BOOL firstKey=TRUE; for (NSString *key in params) { NSString *value=[params objectForKey:key]; if (firstKey) url=[url stringByAppendingString:@"?"]; else url=[url stringByAppendingString:@"&"]; url=[url stringByAppendingString:key]; url=[url stringByAppendingString:@"="]; url=[url stringByAppendingString:value]; firstKey=FALSE; } NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0]; return theRequest; } +(NSURL *) generateWebServiceHTTPGetURL : (NSString *) url: (NSString *) methodName: (NSArray *) keys: (NSArray *) objects { NSDictionary *params = [NSDictionary dictionaryWithObjects:objects forKeys:keys]; NSString *newMethodName; NSURL *resultURL; // We need to start the methodName with a / - since we are using GET Request method newMethodName = @"/"; newMethodName = [newMethodName stringByAppendingString: methodName]; NSLog(@"generateWebServiceHTTPGetURL: newMethodName: %@",newMethodName); url=[url stringByAppendingString:newMethodName]; BOOL firstKey=TRUE; for (NSString *key in params) { NSString *value=[params objectForKey:key]; if (firstKey) url=[url stringByAppendingString:@"?"]; else url=[url stringByAppendingString:@"&"]; url=[url stringByAppendingString:key]; url=[url stringByAppendingString:@"="]; url=[url stringByAppendingString:value]; firstKey=FALSE; } NSLog(@"generateWebServiceHTTPGetURL: URL: %@",(NSString *)url); resultURL = [NSURL URLWithString:url]; return resultURL; } @end [/Code] MyViewController.h (obviously any view controller) [Code] #import <UIKit/UIKit.h> @interface MyViewController : UIViewController { IBOutlet UILabel *lblUserName; IBOutlet UILabel *lblPW; } @property (nonatomic, retain) UILabel *lblUserName; @property (nonatomic, retain) UILabel *lblPW; -(IBAction) callMyWebService: (id) sender; @end [/Code] MyViewController.m [Code] #import "myViewController.h" @implementation myViewController @synthesize lblUserName, lblPW; -(IBAction) callMyWebService: (id) sender { NSURL *theURL; NSArray *keys = [NSArray arrayWithObjects:@"userName",@"passWord", nil]; NSArray *keyvalues = [NSArray arrayWithObjects:lblUserName.text,lblPW.text, nil]; theURL = [WebServiceHelper generateWebServiceHTTPGetURL: @"http://www.mywebsite.com/mywebservice.asmx": @"mywebservicemethod": keys: keyvalues]; // The rest of the code you will have to use NSXMLParser to parse the WS XML } [/Code] I hope the above will help you... maybe some syntax errors... wrote it by hand.... Good luck....[Code]

    #import "WebServiceHelper.h"


    @implementation WebServiceHelper



    /*
    url - string url of web service (including .asmx)
    methodName - string methodname(operation) of webservice
    keys = parameters of web service
    objects = values of each parameter in web service

    example:


    NSArray *keys = [NSArray arrayWithObjects:@"USZip", nil];
    NSArray *keyvalues = [NSArray arrayWithObjects:@"11235", nil];


    [self generateWebServiceURLRequest: @"http://www.mywebsite.com/mywebservice.asmx" : @"getMyData": keys: keyvalues]

    */
    +(NSURLRequest *) generateWebServiceURLRequest : (NSString *) url: (NSString *) methodName: (NSArray *) keys: (NSArray *) objects
    {
    NSDictionary *params = [NSDictionary dictionaryWithObjects:objects forKeys:keys];

    NSString *newMethodName;

    // We need to start the methodName with a / - since we are using GET Request method
    newMethodName = @"/";
    newMethodName = [newMethodName stringByAppendingString: methodName];

    url=[url stringByAppendingString:newMethodName];

    BOOL firstKey=TRUE;
    for (NSString *key in params)
    {
    NSString *value=[params objectForKey:key];
    if (firstKey) url=; else url=;
    url=
    ;
    url=
    ;
    url=
    [url stringByAppendingString:value];
    firstKey=FALSE;
    }

    NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:url]
    cachePolicy:NSURLRequestUseProtocolCachePolicy
    timeoutInterval:60.0];

    return theRequest;
    }


    +(NSURL *) generateWebServiceHTTPGetURL : (NSString *) url: (NSString *) methodName: (NSArray *) keys: (NSArray *) objects
    {
    NSDictionary *params = [NSDictionary dictionaryWithObjects:objects forKeys:keys];

    NSString *newMethodName;

    NSURL *resultURL;

    // We need to start the methodName with a / - since we are using GET Request method
    newMethodName = @"/";
    newMethodName = [newMethodName stringByAppendingString: methodName];

    NSLog(@"generateWebServiceHTTPGetURL: newMethodName: %@",newMethodName);

    url=[url stringByAppendingString:newMethodName];

    BOOL firstKey=TRUE;
    for (NSString *key in params)
    {
    NSString *value=[params objectForKey:key];
    if (firstKey) url=; else url=;
    url=
    ;
    url=
    ;
    url=
    [url stringByAppendingString:value];
    firstKey=FALSE;
    }

    NSLog(@"generateWebServiceHTTPGetURL: URL: %@",(NSString *)url);

    resultURL = [NSURL URLWithString:url];

    return resultURL;
    }

    @end

    [/Code]

    MyViewController.h (obviously any view controller)

    #import <UIKit/UIKit.h> @interface MyViewController : UIViewController { IBOutlet UILabel *lblUserName; IBOutlet UILabel *lblPW; } @property (nonatomic, retain) UILabel *lblUserName; @property (nonatomic, retain) UILabel *lblPW; -(IBAction) callMyWebService: (id) sender; @end [/Code] MyViewController.m [Code] #import "myViewController.h" @implementation myViewController @synthesize lblUserName, lblPW; -(IBAction) callMyWebService: (id) sender { NSURL *theURL; NSArray *keys = [NSArray arrayWithObjects:@"userName",@"passWord", nil]; NSArray *keyvalues = [NSArray arrayWithObjects:lblUserName.text,lblPW.text, nil]; theURL = [WebServiceHelper generateWebServiceHTTPGetURL: @"http://www.mywebsite.com/mywebservice.asmx": @"mywebservicemethod": keys: keyvalues]; // The rest of the code you will have to use NSXMLParser to parse the WS XML } [/Code] I hope the above will help you... maybe some syntax errors... wrote it by hand.... Good luck....[Code]


    #import <UIKit/UIKit.h>


    @interface MyViewController : UIViewController {

    IBOutlet UILabel *lblUserName;
    IBOutlet UILabel *lblPW;

    }


    @property (nonatomic, retain) UILabel *lblUserName;
    @property (nonatomic, retain) UILabel *lblPW;


    -(IBAction) callMyWebService: (id) sender;

    @end

    [/Code]

    MyViewController.m

    #import "myViewController.h" @implementation myViewController @synthesize lblUserName, lblPW; -(IBAction) callMyWebService: (id) sender { NSURL *theURL; NSArray *keys = [NSArray arrayWithObjects:@"userName",@"passWord", nil]; NSArray *keyvalues = [NSArray arrayWithObjects:lblUserName.text,lblPW.text, nil]; theURL = [WebServiceHelper generateWebServiceHTTPGetURL: @"http://www.mywebsite.com/mywebservice.asmx": @"mywebservicemethod": keys: keyvalues]; // The rest of the code you will have to use NSXMLParser to parse the WS XML } [/Code] I hope the above will help you... maybe some syntax errors... wrote it by hand.... Good luck....[Code]


    #import "myViewController.h"

    @implementation myViewController

    @synthesize lblUserName, lblPW;

    -(IBAction) callMyWebService: (id) sender {


    NSURL *theURL;


    NSArray *keys = [NSArray arrayWithObjects:@"userName",@"passWord", nil];
    NSArray *keyvalues = [NSArray arrayWithObjects:lblUserName.text,lblPW.text, nil];



    theURL = [WebServiceHelper generateWebServiceHTTPGetURL: @"http://www.mywebsite.com/mywebservice.asmx": @"mywebservicemethod": keys: keyvalues];


    // The rest of the code you will have to use NSXMLParser to parse the WS XML

    }

    [/Code]



    I hope the above will help you... maybe some syntax errors... wrote it by hand....

    Good luck....
  • blackyEblackyE GermanyPosts: 87Registered Users @
    edited September 2008
    thanks for your reply,


    but i have another question...:rolleyes:

    can i switch the view when i push a button who had the code of the soap service integrated?????????



    thank,
    blackyE
  • varcharvarchar NYCPosts: 138Registered Users @ @
    edited September 2008
    Yes. There are many ways to push or "switch" views.

    Here is way to push the view (assuming you are using navigation controller)

    MyViewController *view1 = [[MyViewController alloc] initWithNibName:@"MyView" bundle:[NSBundle mainBundle]]; self.myViewController = view1; [view1 release]; [self.navigationController pushViewController:self.myViewController animated:YES]; [/Code] Another way would be to do the following (if your app is only view based not nav based) [Code] MainViewController *aSecondView = [[MainViewController alloc] initWithNibName:@"MainView" bundle:nil]; [self setMainViewController:aSecondView]; [aSecondView release]; [UIView beginAnimations:nil context:NULL]; [UIView setAnimationDuration:2.0]; [UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:window cache:YES]; [viewController.view removeFromSuperview]; [self.window addSubview:[mainViewController view]]; [UIView commitAnimations]; [/Code][Code]

    MyViewController *view1 = [[MyViewController alloc] initWithNibName:@"MyView" bundle:[NSBundle mainBundle]];
    self.myViewController = view1;
    [view1 release];

    [self.navigationController pushViewController:self.myViewController animated:YES];

    [/Code]


    Another way would be to do the following (if your app is only view based not nav based)

    MainViewController *aSecondView = [[MainViewController alloc] initWithNibName:@"MainView" bundle:nil]; [self setMainViewController:aSecondView]; [aSecondView release]; [UIView beginAnimations:nil context:NULL]; [UIView setAnimationDuration:2.0]; [UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:window cache:YES]; [viewController.view removeFromSuperview]; [self.window addSubview:[mainViewController view]]; [UIView commitAnimations]; [/Code][Code]

    MainViewController *aSecondView = [[MainViewController alloc] initWithNibName:@"MainView" bundle:nil];
    [self setMainViewController:aSecondView];
    [aSecondView release];

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:2.0];
    [UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:window cache:YES];
    [viewController.view removeFromSuperview];
    [self.window addSubview:[mainViewController view]];
    [UIView commitAnimations];

    [/Code]
  • blackyEblackyE GermanyPosts: 87Registered Users @
    edited September 2008
  • varcharvarchar NYCPosts: 138Registered Users @ @
    edited September 2008
    Let me know what you want to do... I can write the code for you if you wish....
  • gagandeepbgagandeepb Posts: 88Registered Users
    edited September 2008
    Hi Trilitech,
    I read your whole post.It wrks great. My app need to send more complex data for now i am sending xml as a string parameter in url. But it always says bad url. When i construct same url and send it through browser it wrks and send response but from NSURLRequest object it becomes bad url. i am also using UTF8String encoding.
    Any idea??
  • blackyEblackyE GermanyPosts: 87Registered Users @
    edited September 2008
    @varchar

    thanks for your help.

    i need a code that connect to a login.asp page. when i have the request from the page that it ask me for a username and password.
    when i connect successful that the view switch and i can show my status of an order.
    is that possible?

    i`m sorry for the bad english!!!
  • blackyEblackyE GermanyPosts: 87Registered Users @
    edited September 2008
    i have some error with the code


    -(IBAction)showandanswer:(id)sender {
    buttonViewController *ansicht2 = [[buttonViewController alloc] initWithNibName:@"Login" bundle:nil];
    [self view:ansicht2]; here is the error: buttonViewController may not respond to -view
    [ansicht2 release];

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:2.0];
    [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:view2 cache:YES];
    [self. view2 removeFromSuperview];
    [self.view2 addSubview:view2];
    [UIView commitAnimations];
    }




    What does the error exactly means? I have try very much eventualities to fit the error.
    Is there no sample code or tutorial out there where i can look at?

    thanks,
    blackyE
  • bmzerobmzero Posts: 20Registered Users
    edited September 2008
    First off, thanks for the code samples. They have helped me tremendously. I'm a .NET web developer in transition. :-)

    I have my application calling a .NET web service. The service returns only an integer value wrapped in "<int></int>". That is the full response from the service. Example: <int>456</int>

    The parser returns the value correctly when I check it in a breakpoint during debugging (value is at currentElementValue), but I can't seem to get the value into something usable within the application.

    I'm assuming that I need to use objectAtIndex somehow, but all of my efforts have failed.

    Do you guys have any suggestions?
  • varcharvarchar NYCPosts: 138Registered Users @ @
    edited September 2008
    BMZero,

    Glad that this thread is helping you...

    I too am a .NET Developer and recently in past few months been staying up ever night learning objective-C and SDK very well... :)

    To answer your question:


    I am assuming you are familiar with the XMLParser, since that seems to be best (and probably only way) to parse XML...

    See below... it may help you....


    - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{ // NSLog(@"found this element: %@", elementName); currentElement = [elementName copy]; if ([elementName isEqualToString:@"int"]) { myInt = [[NSMutableString alloc] init]; // Notice I am alloc as a NSmutablestring, you can change this to int (not not alloc it) } } - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{ if ([elementName isEqualToString:@"int"]) { // Below is a hack, because the vars do not get saved between methods finalMyInt = @""; finalMyInt = [finalNearByLatitudes stringByAppendingString:nearbyLatitudes]; } - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{ if ([currentElement isEqualToString:@"int"]) { [MyInt appendString:string]; } // NSLog(@"found characters: %@", string); } [/Code][Code]



    - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
    // NSLog(@"found this element: %@", elementName);
    currentElement = [elementName copy];
    if ([elementName isEqualToString:@"int"]) {
    myInt = [[NSMutableString alloc] init]; // Notice I am alloc as a NSmutablestring, you can change this to int (not not alloc it)


    }

    }

    - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{

    if ([elementName isEqualToString:@"int"]) {
    // Below is a hack, because the vars do not get saved between methods
    finalMyInt = @"";
    finalMyInt = [finalNearByLatitudes stringByAppendingString:nearbyLatitudes];
    }

    - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{

    if ([currentElement isEqualToString:@"int"]) {
    [MyInt appendString:string];
    }

    // NSLog(@"found characters: %@", string);
    }

    [/Code]
  • bmzerobmzero Posts: 20Registered Users
    edited September 2008
    Wow, I feel like I completely overlooked that in the previously provided sample code. I tried something similar to that but it didn't work, so I gave up on that method. I wish I had kept on with it now.

    I really appreciate the reply. Thanks, it's just what I needed to see.
  • varcharvarchar NYCPosts: 138Registered Users @ @
    edited September 2008
    As they say: "That's what discussion boards are for...."

    Glad I can help....
  • nieljacobsnieljacobs Posts: 1New Users
    edited September 2008
    Hi guys

    I'm new to iphone programming (also coming from .net). I'm really struggling to get this working. I'm trying to test with a public webservice:
    TimeService Web Service

    The url I get from getRestUrl is: http://www.nanonull.com/TimeService/TimeService.asmx/getCityTime?city=london
    Is this correct? If I submit this url I get runtime errors from the web service.

    This is my first iPhone project so I'm probably missing something basic here.
    Thanks for your help
  • Black ScytherBlack Scyther Posts: 36Registered Users
    edited September 2008
    How about this: Weather Web Service. I tried different solutions but without success.
  • naitnait Posts: 3New Users
    edited September 2008
    I've tried this, several times over, with WCF and .net 2.0 asp.net web services, and I can't get it to work. The iphone code works just fine, but I can't find out how to get the web service to accept calls over GET. Google turns up nothing particularly useful, and digging through the settings for the project, IIS, and other system settings doesn't turn anything up either. I figure I must just be overlooking something. All I can find is stuff saying "turn off POST and GET to your .net web services" as they are pretty insecure. I am in the process of writing an actual library for soap calls as opposed to rest, but I'm on a really tight schedule and if I can get this to work, I would rather use it.

    Trilitech, thanks a ton for posting this information. It seems your efforts are appreciated by many. You're the first hit for the search string "soap iphone rest" in google :).
«134
Sign In or Register to comment.