0
votes

I've been scouring the web for a few hours looking for a solution to a problem that I need to resolve with a Xamarin.iOS app that I've been developing. Most, if not all, of our customers in the field need to upload pictures that they attach to work orders (tickets), which go to an FTP on our backend. My coworker developed the Android app and from him I took the current method, based off of an FtpRequest casted to an FtpWebRequest. It works 90% of the time and uploads to the server reasonably quick if the user has a decent connection.

The problem? I need 100% of the time, and I need it to be in the background. I found that NSUrlSession seems to be my best bet for solving this issue, as it's native to iOS and has support for backgrounding. My only issue is that when I try to create the UploadTask with session.CreateUploadTask, it says "cannot read file at (path)" where path is: file://var/mobile/Containers/Data/Application/850CB1FE-9C2D-456C-8B5F-921DC8D5CEF5/Documents/PolarisPictures2/VUPSXOUTA722002799CMC5022017103109544681088_1.jpeg. I've already confirmed that the file does exist on that path via printing out the file name using foreach( var file in Directory.EnumerateFiles(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "PolarisPictures2") ) Without using the file:// protocol, the error returns with "...is not a valid file:// url." So is it that I'm not accessing the file properly, or is it that there's simply no way to do what I'm trying to do?

And if there is no way, could anyone provide a solution that would best achieve the backgrounding capabilities that I require?

Appreciate it, guys.

Thanks.

Here's my code:

NSUrlSession session = null;
        NSUrlSessionConfiguration config = NSUrlSessionConfiguration.CreateBackgroundSessionConfiguration("com.PolarisFTPUpload.BackgroundSession");
        session = NSUrlSession.FromConfiguration(config, (NSUrlSessionDelegate)new MySessionDelegate(), new NSOperationQueue());
        string docs = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
        docs = docs.Replace("/var", "file://var");
        string filepath = System.IO.Path.Combine(docs, "PolarisPictures2/VUPSXOUTA722002799CMC5022017103109544681088_1.jpeg");
        Console.WriteLine(filepath);
        string UploadURLString = "ftp://myftpUser:myftpPass@myftpIP:Port/Pictures/Database" + "/" + DateTime.Today.Year + "/" + DateTime.Today.Month + "/" + DateTime.Today.Day + "/";
        NSUrlSessionUploadTask uploadTask;
        NSUrl uploadURL = NSUrl.FromString(UploadURLString);
        NSUrlRequest req = NSUrlRequest.FromUrl(uploadURL);
        uploadTask = session.CreateUploadTask(req, NSUrl.FromString(filepath));
2

2 Answers

2
votes

Neither NSURLSession nor its predecessor, NSURLConnection, support the FTP PUT command. The only Apple API that supports FTP uploads is CFFTPStream, which is ancient, deprecated, and strongly discouraged for new development.

Either way, you should not under any circumstances use FTP. Period. It is fundamentally impossible to make FTP secure, because passwords are sent in cleartext across the network.

Instead, you should write a simple bit of PHP code on your web server that accepts file uploads, and use HTTPS uploads. Not only is that approach more secure, it is also supported with NSURLSession.

See Secure PHP File Upload Script for more information on the web site of things, and see Apple's NSURLSession Programming Guide for help with the uploads on the iOS side.

2
votes

There should be three / with file prefix. The prefix should be file:///, not file://.

You can just use NSUrl.FromFilename(filepath) to get this url without replacing the prefix.