11

I have a WCF service hosted and I'm trying to use it within an iPhone app as a JSON POST request. I plan on using the JSON serializer later, but this is what I have for the request:

    NSString *jsonRequest = @"{\"username\":\"user\",\"password\":\"letmein\"}";
    NSLog(@"Request: %@", jsonRequest);

    NSURL *url = [NSURL URLWithString:@"https://mydomain.com/Method/"];

    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
    NSData *requestData = [NSData dataWithBytes:[jsonRequest UTF8String] length:[jsonRequest length]];

    [request setHTTPMethod:@"POST"];
    [request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
    [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
    [request setValue:[NSString stringWithFormat:@"%d", [requestData length]] forHTTPHeaderField:@"Content-Length"];
    [request setHTTPBody: requestData];

    [NSURLConnection connectionWithRequest:[request autorelease] delegate:self];

In my data received I'm just printing it to the console:

- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    NSMutableData *d = [[NSMutableData data] retain];
    [d appendData:data];

    NSString *a = [[NSString alloc] initWithData:d encoding:NSASCIIStringEncoding];

    NSLog(@"Data: %@", a);
}

And within this response I get this message:

Data: <?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>Request Error</title>
    <style>
        <!-- I've took this out as there's lots of it and it's not relevant! -->
    </style>
  </head>
  <body>
    <div id="content">
      <p class="heading1">Request Error</p>
      <p xmlns="">The server encountered an error processing the request. Please see the <a rel="help-page" href="https://mydomain.com/Method/help">service help page</a> for constructing valid requests to the service.</p>
    </div>
  </body>
</html>

Does anyone know why this happens and where I'm going wrong?

I've read about using ASIHTTPPost instead but I can't get the demo to run in iOS4 :(

Thanks

EDIT:

I've just used to CharlesProxy to sniff out what's happening when I call from the iPhone (Simulator) and this is what it gave me: alt text

The only thing strange I've noticed is it says "SSL Proxying not enabled for this host: enable in Proxy Settings, SSL locations". Does anyone know what this means? (This also happens in my working windows client).

I've just ran this on my windows client and the only thing that is different is the Request and Response text which is encrypted. Am I missing something in order to use a secure HTTP connection to do this?

NEW EDIT: This works with a non-HTTPS request such as: http://maps.googleapis.com/maps/api/geocode/json?address=UK&sensor=true. So I guess the problem is getting the iPhone to send the POST properly over SSL?

I am also using these methods:

- (void) connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
    if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
    {
        [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]
        forAuthenticationChallenge:challenge];
    }

    [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}

- (void) connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
{
    if([[protectionSpace authenticationMethod] isEqualToString:NSURLAuthenticationMethodServerTrust])
    {
        return YES;
    }
}

This allows me to get this far. If I don't use them I get an error sent back saying:

The certificate for this server is invalid. You might be connecting to a server that is pretending to be “mydomain.com” which could put your confidential information at risk.

ingh.am
  • 24,319
  • 41
  • 126
  • 176

4 Answers4

12

FIXED!

Changed:

[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];

to:

[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];

You also need these two methods:

- (void) connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
    if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
    {
        [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]
        forAuthenticationChallenge:challenge];
    }

    [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}

- (void) connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
{
    if([[protectionSpace authenticationMethod] isEqualToString:NSURLAuthenticationMethodServerTrust])
    {
        return YES;
    }
}
ingh.am
  • 24,319
  • 41
  • 126
  • 176
  • btw, didn't you forget to "return NO;" in the last line of the last method? – Artem Mar 26 '12 at 14:42
  • I'm not sure, I return YES to a void method. Can't remember why now. – ingh.am Mar 26 '12 at 14:44
  • @ing0 can you translate this line into swift plz [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; – Qadir Hussain Sep 25 '14 at 07:24
  • @QadirHussain Sorry I haven't written much swift. Check out this answer though: http://stackoverflow.com/a/24321320/143979 – ingh.am Sep 26 '14 at 09:59
3

I don't know Objective C at all, but try setting the Accept header to application/json instead of application/jsonrequest.

Jon
  • 14,742
  • 8
  • 49
  • 58
  • Tried that earlier. Should it be like this anyway? Just did it again and I still get the same response! :( – ingh.am Nov 03 '10 at 10:22
  • 1
    `application/json` is definitely the correct MIME type for JSON data. See http://stackoverflow.com/questions/477816/the-right-json-content-type – Jon Nov 03 '10 at 10:23
  • Are you sure that your web service accepts data in url-encoded format and responds in json format? It will be easy to figure out the issue, if you execute a curl command and program the same in obj-C – Chaitanya Nov 03 '10 at 10:26
  • would be helpful also if you posted the source and particularly config for your WCF service. Also, have you tried visiting the service help page that's in the error message? – Jon Nov 03 '10 at 10:27
  • Unfortunatly I didn't write the service. I have a .NET app doing exactly what I want using a similar process. So I know it's not a server issue! – ingh.am Nov 03 '10 at 10:34
  • well then, get a tool like Fiddler, and compare what your .NET app and your iPhone app are sending over the wire - request headers and content - and if the iPhone app isn't the same then you have an idea where to look next. – Jon Nov 03 '10 at 10:37
  • Btw, I did visit the service help page. It's just a dump of what I should expect in XML and in JSON. – ingh.am Nov 03 '10 at 11:17
  • The comparisons are the same except for the encrypted request and response texts... :( – ingh.am Nov 03 '10 at 18:51
0

change

NSData *requestData = [NSData dataWithBytes:[jsonRequest UTF8String] length:[jsonRequest length]];

to

NSData *requestData = [jsonRequest dataUsingEncoding:NSUTF8StringEncoding];
Maulik Vekariya
  • 544
  • 7
  • 19
0

dic is NSMutable Dictionary with object and keys. baseUrl is your server webservice url.

 NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dic
                                                       options:NSJSONWritingPrettyPrinted error:nil];
    NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
   NSString *encodedString = [jsonString base64EncodedString];

    NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@wsName",baseUrl]];
    NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:url];
    [theRequest addValue: @"text/xml; charset=utf-8" forHTTPHeaderField:@"Content-Type"];
    [theRequest setHTTPMethod:@"POST"];
    [theRequest setValue:encodedString forHTTPHeaderField:@"Data"];
Vibhooti
  • 1,183
  • 2
  • 9
  • 20