Before I start: I'm programming for Iphone, using objective C.
I have already implemented a call to a web service function using NSURLRequest and NSURLConnection and SOAP. The function then returns a XML with the info I need.
The code is as follows:
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"
"<function xmlns=\"http://tempuri.org/\" />\n"
"</soap:Body>\n"
"</soap:Envelope>\n"];
NSURL *url = [NSURL URLWithString:#"http://myHost.com/myWebService/service.asmx"]; //the url to the WSDL
NsMutableURLRequest theRequest = [[NSMutableURLRequest alloc] initWithURL:url];
NSString *msgLength = [NSString stringWithFormat:#"%d",[soapMessage length]];
[theRequest addValue:#"text/xml; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
[theRequest addValue:msgLength forHTTPHeaderField:#"Content-Lenght"];
[theRequest setHTTPMethod:#"POST"];
[theRequest addValue:#"myhost.com" forHTTPHeaderField:#"Host"];
[theRequest addValue:#"http://tempuri.org/function" forHTTPHeaderField:#"SOAPAction"];
[theRequest setHTTPBody:[soapMessage dataUsingEncoding:NSUTF8StringEncoding]];
theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
I basically copy and modified the soap request the web service gave as an example.
i also implemented the methods
didRecieveResponse
didRecieveAuthenticationChallenge
didRecievedData
didFailWithError
connectionDidFinishLoading.
And it works perfectly.
Now I need to send 2 parameters to the function: "location" and "module".
I tried modifying the soapMessage like this:
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 xmlns=\"http://tempuri.org/\" />\n"
"<m:GetMonitorList>\n"
"<m:location>USA</m:location>\n"
"<m:module>DEVELOPMENT</m:module>\n"
"</m:GetMonitorList>\n"
"</soap:Body>\n"
"</soap:Envelope>\n"];
But is not working...any thoughts how should I modify it?
Extra info:
it seems to be working... kind of.
But the webservice return nothing.
During the connection, the method
didReceiveResponse execute once and
the didFinishLoading method executes
as well. But not even once the method
didReceiveData.
I wonder if, even though there is no
USA locations, it will still send at
least something?
is there a way to know which are the
parameters the function is waiting
for?
I don't have access to the source of the webservice but i can access the WSDL.
You are probably passing the service a message that is not valid. You should have a look at the WSDL; there should be one or more schemas or schema documents listed inside it. Those will tell you how you can construct the body of the SOAP message.
I was experiencing your problem before when i develop the code as similar you given.Check your again WSDL file and you need to request a single SOAP message in the single class otherwise your methods(given in first part) of your question will be clash.
Please go to the following link, I hope, it will help you...
1) kosmaczewski.net
2) http://icodeblog.com/2008/11/03/iphone-programming-tutorial-intro-to-soap-web-services/
3) http://viium.com
Related
I have been trying out for a while using Box 2.0 API to upload a file from Objective C client to my Box folder. I've read a few posts from:
how to send form data in a programmatic file upload in box api 2.0
API 2.0 how to upload file with POSTMAN?
I've tried successfully using the Curl, as mentioned in the documentation, but always get a 404 when trying to create a NSMutableUrlRequest.
This is my code:
NSURL *URL = [NSURL URLWithString:#"https://api.box.com/2.0/files/content"];
urlRequest = [[NSMutableURLRequest alloc]
initWithURL:URL cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:30];
[urlRequest setHTTPMethod:#"POST"];
AppDelegate *appDelegate = [AppDelegate sharedDelegate];
NSString *p = [NSString stringWithFormat:#"BoxAuth api_key=%#&auth_token=%#",API_KEY,appDelegate.boxAuthToken];
[urlRequest setValue:p forHTTPHeaderField:#"Authorization"];
[urlRequest setValue:#"multipart/form-data, boundary=AaB03x" forHTTPHeaderField:#"Content-Type"];
NSString *postBody = #"--AaB03x"
#"content-disposition: form-data; name=\"filename\"; filename=\"test.txt\";"
#"folder_id=466838434"
#"Content-type: text/plain"
#""
#"testing box api 2.0"
#""
#"--AaB03x--";
NSData *data = [postBody dataUsingEncoding:NSUTF8StringEncoding];
[urlRequest setHTTPBody:data];
[urlRequest setValue:[NSString stringWithFormat:#"%d",[data length]] forHTTPHeaderField:#"Content-Length"];
There are a couple of problems that I see with the way you're constructing the postBody. Having newlines between string literals in your code simply concatenates them. You actually need to have carriage return and line feed to separate different parts of your HTTP body. Also, you mashed both of your form elements in one. The file and folder_id are two separate form elements. You could try something like this:
NSString *postBody = #"\r\n--AaB03x\r\n"
"Content-Disposition: form-data; filename=\"test.txt\"\r\n"
"Content-Type: text/plain\r\n\r\n"
"testing box api 2.0"
"\r\n--AaB03x\r\n"
"Content-Disposition: form-data; name=\"folder_id\";\r\n\r\n"
"0"
"\r\n--AaB03x--\r\n\r\n";
I think that should work provided everything else is set up properly.
Use http://allseeing-i.com/ASIHTTPRequest/
It makes dealing with multipart forms much easier!
I am trying to set up a cache, however the method I am using 'as below' is not being accessed by the thread.
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse
I am initializing the connection like this, and connectionDidFinishLoading is accessed so I am not sure what I am missing.
- (IBAction)searchRequest:(NSData *)postBodyData
{
//Set database address
NSMutableString *databaseURL = [[NSMutableString alloc] initWithString:#"https://127.0.0.1:88"];
NSURL *url = [NSURL URLWithString:databaseURL];
NSString *postLength = [NSString stringWithFormat:#"%d", [postBodyData length]];
//SynchronousRequest to grab the data, also setting up the cachePolicy
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:5.0]; //if request dose not finish happen within 60 second timeout.
// NSInputStream *fileStream = [NSInputStream inputStreamWithData:postBodyData];
[request setHTTPMethod: #"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/octet-stream" forHTTPHeaderField:#"content-type"];
[request setHTTPBody:postBodyData];
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:request delegate:self];
if (theConnection) {
// Create the NSMutableData to hold the received data.
// receivedData is an instance variable declared elsewhere.
receivedData = [NSMutableData data];
} else {
// Inform the user that the connection failed from the connection:didFailWithError method
}
}
any help would be appreciated.
connection:willCacheResponse: is only called in cases when the response will be cached. POST requests are not cacheable in most cases. (More details: Is it possible to cache POST methods in HTTP?)
You should probably look at something like MKNetworkKit which handles a lot of this kind of caching, particularly for REST protocols.
You can also look at Drop-in offline caching for UIWebView. You'd have to modify it significantly, but NSURLProtocol can be used to solve this kind of problem. AFCache is currently working to integrate this approach, and is another toolkit to consider. (Read through the comments in the blog post for more background on the issues.)
I am trying to upload the document using Google API through my iPhone App. Here is the code which I am using:
NSString *authorizationHeader = [NSString stringWithFormat:#"GoogleLogin auth=\"%#\"" ,[another objectAtIndex:1]];
NSURL *url2 = [NSURL URLWithString:#"docs.google.com/feeds/documents/private/full"];
NSMutableURLRequest *urlRequest2 = [[NSMutableURLRequest alloc]initWithURL:url2];
[urlRequest2 setHTTPMethod:#"POST"];
[urlRequest2 setValue:#"2.0" forHTTPHeaderField:#"GData-Version"];
[urlRequest2 setValue:authorizationHeader forHTTPHeaderField:#"Authorization"];
[urlRequest2 setValue:Length forHTTPHeaderField:#"Content-Length"];
[urlRequest2 setValue:#"text/html" forHTTPHeaderField:#"Content-Type"];
[urlRequest2 setValue:slugStr forHTTPHeaderField:#"Slug"];
[urlRequest2 setHTTPBody:audioData];
Where authorizationHeader contains my GoogleLogin auth=theToken
By running this code I get the following response from the server
<HTML>
<HEAD> <TITLE>Token invalid</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
<H1>Token invalid</H1>
<H2>Error 401</H2>
</BODY>
</HTML>
I don't know where I am making the mistake. Is there an error in my header or am I passing the wrong parameters?
Shouldn't the url in the is prefixed with http:// when creating the NSURL?
NSURL *url2 = [NSURL URLWithString:#"http://docs.google.com/feeds/documents/private/full"];
I am attempting to implement an online leaderboard in a game app for iOS, using Django to process POST requests from the iDevice and store the scores. I have figured out how to get Django to serialize the objects to XML, and my iPhone can read and display the scores. However, I can't for the life of me get my iPhone to POST XML to my Django server.
Below is the function I am using to post the scores...
iOS (Objective-C) Controller:
- (void) submitHighScore {
NSLog(#"Submitting high score...");
NSString *urlString = HIGH_SCORES_URL;
NSURL *url = [NSURL URLWithString: urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL: url];
[request setHTTPMethod: #"POST"];
[request setValue: #"text/xml" forHTTPHeaderField: #"Content-Type"];
NSMutableData *highScoreData = [NSMutableData data];
[highScoreData appendData: [[NSString stringWithFormat: #"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"] dataUsingEncoding: NSUTF8StringEncoding]];
[highScoreData appendData: [[NSString stringWithFormat: #"<player_name>%#</player_name", #"test"] dataUsingEncoding: NSUTF8StringEncoding]];
[highScoreData appendData: [[NSString stringWithFormat: #"<score>%d</score>", 0] dataUsingEncoding: NSUTF8StringEncoding]];
[highScoreData appendData: [[NSString stringWithFormat: #"</xml>"] dataUsingEncoding: NSUTF8StringEncoding]];
[request setHTTPBody: highScoreData];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible: YES];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest: request
delegate: self];
if (!connection) {
NSLog(#"Request to send high scores appears to be invalid.");
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible: NO];
}
}
The above method succeeds in sending the request, and interprets it correctly as CONTENT_TYPE: text/xml, but the Django view that processes the request can't seem to make any sense of it, interpreting it almost as if it was merely plain text. Below is my Django view...
Django (Python) view:
from django.http import HttpResponse, HttpResponseBadRequest
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.core import serializers
from django.core.exceptions import ValidationError
from django.views.decorators.csrf import csrf_exempt
from modologger.taptap.models import HighScore
#csrf_exempt
def leaderboard( request, xml = False, template_name = 'apps/taptap/leaderboard.html' ):
"""Returns leaderboard."""
if xml == True: # xml is set as True or False in the URLConf, based on the URL requested
if request.method == 'POST':
postdata = request.POST.copy()
print postdata
# here, postdata is evaluated as:
# <QueryDict: {u'<?xml version': [u'"1.0" encoding="UTF-8" ?><player_name>test</player_name<score>0</score></xml>']}>
for deserialized_object in serializers.deserialize('xml', postdata): # this fails, returning a 500 error
try:
deserialized_object.object.full_clean()
except ValidationError, e:
return HttpResponseBadRequest
deserialized_object.save()
else:
high_score_data = serializers.serialize( 'xml', HighScore.objects.all() )
return HttpResponse( high_score_data, mimetype = 'text/xml' )
else:
high_scores = HighScore.objects.all()
return render_to_response( template_name, locals(), context_instance = RequestContext( request ) )
To be honest, I'm not sure whether the problem lies in the Objective-C or in the Django code. Is the Objective-C not sending the XML in the right format? Or is the Django server not processing that XML correctly?
Any insight would be much appreciated. Thanks in advance.
Update:
I got it to work, by editing the iOS Controller to set the HTTPBody of the request like so:
NSMutableData *highScoreData = [NSMutableData data];
[highScoreData appendData: [[NSString stringWithFormat: #"player_name=%#;", #"test"] dataUsingEncoding: NSUTF8StringEncoding]];
[highScoreData appendData: [[NSString stringWithFormat: #"score=%d", 0] dataUsingEncoding: NSUTF8StringEncoding]];
[request setHTTPBody: highScoreData];
For some reason putting a semicolon in there got Django to recognize it, assign the values to a new instance of a HighScore class, and save it. The logging on the test server indicates request.POST is <QueryDict: {u'score': [u'9'], u'player_name': [u'test']}>.
Still not quite sure what to make of all this.
As per Radu's suggestion, I took a look at highScoreData with NSLog, right after appending it to request.HTTPBody, and the result is <706c6179 65725f6e 616d653d 74657374 3b73636f 72653d39>.
I'm a huge Obj-C noob, so again, any help is appreciated! Thanks again.
Since you control both sides, I'd drop the complexity of xml encoding the data and use RestKit or some other framework that makes it easy to communicate with Django.
how to send a transition receipt along with a product identifier to my server using HTTP POST method? Should I have to encode the product identifier using base64?
I am getting this response:
{"message" : "21002: java.lang.IllegalArgumentException: propertyListFromString parsed an object, but there's still more text in the string. A plist should contain only one top-level object. Line number: 1, column: 2478.", "error" : 1}
even after I am encoding the transition receipt with base64 encoding...
This is what I am doing:
NSString *bodyString = [NSString stringWithFormat:#"product_id=%#&receipt_data=%#",self.currentProductIdentifer,
[self.productReceiptData base64Encoding]];
NSData *bodyData = [bodyString dataUsingEncoding:NSUTF8StringEncoding
allowLossyConversion:YES];
NSAssert(bodyData!=nil,#"HTTP Body is empty !");
//posting the data to server
NSMutableURLRequest *theRequest=[NSMutableURLRequest requestWithURL:
[NSURL URLWithString:inUrlString]
cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
[theRequest setHTTPMethod:#"POST"];
[theRequest setHTTPBody:inData]; //inData is http body(bodyData) created above
// create the connection with the request // and start loading the data
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];