Search code examples
iosobjective-c.net-core

NSURLSessionDataTask Fail to upload audio file to server


I know this question been asked before. But None of the answers worked for me.

What is the requirements:
on iOS app, user to be able to record a short audio file (30sec) then upload it to the server using https request.
The recording and saving temporary on the phone works very well.
But I couldn't get the upload part to work.

My code to upload file on the API side as follow. Tested it with Postman, works very well. File received and saved as intended.

[HttpPost]
public async Task<IActionResult> UploadFile([FromForm] IFormFile file, [FromForm] string name)
    {
        try
        {
            if(webHostEnvironment == null)
            {
                throw new SqlNullValueException("webHostEnvironment is null");
            }

            if (webHostEnvironment.ContentRootPath == null)
            {
                throw new SqlNullValueException("webHostEnvironment.ContentRootPath is null");
            }


            if(file == null)
            {
                throw new SqlNullValueException("File is null");
            }

            String path = Path.Combine(webHostEnvironment.ContentRootPath,  "uploads");              
            if (file.Length > 0)
            {
                string filePath = Path.Combine(path, file.FileName);
                using (Stream fileStream = new FileStream(filePath, FileMode.Create))
                {
                    await file.CopyToAsync(fileStream);
                }
            }
            return BuildResponse(Ok().StatusCode, name);
        }
        catch(Exception ex)
        {
            throw new Exception(ex.Message );
        }
    }

Here's is my Objective-C code to upload the file:

-(void)uploadFile:(NSData*)fileData{
if(fileData != nil){
    NSString *fileName = self.temporaryRecFile.path.lastPathComponent;
    NSString *urlString = @"some url";//upload file url
    
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
    [request setURL:[NSURL URLWithString:urlString]];
    [request setHTTPMethod:@"POST"];
    NSString *boundary = @"---------------1234567890";
    NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
    [request addValue:contentType forHTTPHeaderField:@"Content-Type"];
    
    
    NSMutableData *bodyData = [[NSMutableData alloc] init];
    [bodyData appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [bodyData appendData:[[NSString stringWithString:[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"userfile\"; filename=\"%@\"\r\n", fileName]] dataUsingEncoding:NSUTF8StringEncoding]];
    [bodyData appendData:[@"Content-Type: application/octet-stream\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    [bodyData appendData:[NSData dataWithData:fileData]];
    [bodyData appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    
    [request setHTTPBody:bodyData];
            
    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
        dispatch_async(dispatch_get_main_queue(), ^{
            
            NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
            NSInteger responseStatusCode = [httpResponse statusCode];
            
            if(error != nil)
                NSLog(@"error uploading file %@", error.localizedDescription);
            else{
                NSLog(@"response: %lu", responseStatusCode);
                NSLog(@"response: %@", data);
                NSLog(@"response: %@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
            }
        });
    }];
    
    [dataTask resume];
}

} The answer I get is :

response: {"code":500,"reason":"File is null"}

Instead of NSURLSessionDataTask I tried to use NSURLSessionUploadTask but with no luck. I got:

Failed to read the request form. Multipart body length limit 16384 exceeded

Since Postman works very well to upload file using API endpoint. Then the problem must be on the iOS app side.
Any ideas what might be the problem? Thanks!


Solution

  • Thanks to @Paulw11 who mentioned the inconsistency issue.

    Took a fresh look at my code on both sides and realized that I made a mistake on the iOS form by calling the file as userfile. API expects file. So there should be two choices here:
    1- Change and rename userfile here: Content-Disposition: form-data; name=\"userfile\"; to file so that API recognizes it.
    2- Or keep any custom name of your choice and modify the API as follow:

        public async Task<IActionResult> UploadFile([FromForm(Name = "userfile")] IFormFile file, [FromForm(Name = "filename")] string filename){
          //upload logic here    
        }
    

    And that solved my problem and file is now uploaded!