Calling a .NET web service endpoint with NSURLSessionUploadTask

I have been going through the process of removing open source components from my apps when Cocoa Touch and the associated frameworks catch up with what I need to do.

Let’s say for the sake of argument you have a .NET web service that looks like this:

using System;
using System.Web.Script.Services;
using System.Web.Services;
 
namespace My_WebRole
{
    /// <summary>
    /// Summary description for CreateCustomer
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    [ScriptService]
    // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
    // [System.Web.Script.Services.ScriptService]
    public class CreateCustomer : WebService
    {
        [WebMethod]
        [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
        public string Create()
        {
            try
            {
                var myName = Context.Request.Form["MyName"];
                var companyName = Context.Request.Form["CompanyName"];
                var db = new MyServicesDataContext();
                var row = new CustomerInformation { MyName = myName, CompanyName = companyName, CreationDate = DateTime.Now };
                db.CustomerInformations.InsertOnSubmit(row);
                db.SubmitChanges();
            }
            catch (Exception ex)
            {
                return ex.ToString();
            }
            return "OK";
        }
    }
}

The NSURLSessionUploadTask class was added in iOS 7, which is sufficiently long enough ago to be stable to implement. (As long as your app is going to require iOS 7 or newer, of course.)

Here is what the code looks like that calls the above web service:

+ (BOOL)pushTheData:(NSString *)myName companyName:(NSString *)companyName
{
    NSMutableString *urlString = [NSMutableString stringWithString:PUSH_DATA_URL];
    NSString *boundary = [NSString boundaryString];
    NSMutableData *body = [NSMutableData data];
 
    [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", @"MyName"] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"%@\r\n", myName] dataUsingEncoding:NSUTF8StringEncoding]];
 
    [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", @"CompanyName"] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"%@\r\n", companyName] dataUsingEncoding:NSUTF8StringEncoding]];
 
    [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
 
    NSURL *url = [NSURL URLWithString:urlString];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [request setHTTPMethod:@"POST"];
    [request addValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary] forHTTPHeaderField:@"Content-Type"];
 
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    configuration.HTTPAdditionalHeaders = @ { @"Content-Type"  : [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary] };
    NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
 
    NSURLSessionUploadTask *task = [session uploadTaskWithRequest:request fromData:body completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (error)
        {
            // handle the error
            return;
        }
 
        NSLog(@"Response: %@", [data utf8String]);
        // do something here
    }];
 
    [task resume];
 
    return YES;
}

The above method uses a category that I have set up off of NSString that creates a new boundary string each time it is called. Here is that method:

+ (NSString *)boundaryString
{
    NSString *uuidStr = [[NSUUID UUID] UUIDString];
    return [NSString stringWithFormat:@"Boundary-%@", uuidStr];
}

BTW, Happy Birthday to Jeff Beck. He has a new album coming out soon, and I can’t wait to hear it.

Leave a Reply