In this post I’ll share with you how to upload a files from a Windows Phone application to a web service via HTTP POST. I’ll be using ASP.NET MVC to create a simple service that allows you to post multi-part form data over HTTP, and a Windows Phone 8 project.
Surprisingly enough, seems to me that there are very few examples available on the web, about how to achieve such a basic feature. It might be because most apps will commonly use popular services like Facebook or Twitter, or established cloud services where APIs and examples exist. However, the moment you want to create your own service to upload photos or files from your mobile app, working coding samples start to mingle.
For the file upload web service, you can use WCF, Web API or ASP.NET MVC (or any other web services technology for that matter), as long as you can provide an endpoint that accepts an http POST request using multipart form data. I previously published a post on how to implement the upload service. Check it out for details and step-by-step instructions. You can also download the sample project here.
Let’s now create the Windows Phone 8 client application that will upload the file. In this case, we will create a simple application that will allow the user to pick a picture from the phone pictures library and upload it to the service.
Open Visual Studio and create a new empty Windows Phone 8 application. Modify the layout of the UI to provide a simple interface to choose a picture, display it and then upload it.
Next, let’s create the functionality to select an existing photo from the phone’s picture library. The code below uses the WP8 PhotoChooserTask to achieve exactly that. Notice that we are attaching an event handler to the completed event, so we know when the user chose the picture.
public partial class MainPage : PhoneApplicationPage{// Image stream variablesprivate MemoryStream photoStream;private string fileName;// PhotoChooserTask definitionPhotoChooserTask photoChooserTask;// Constructorpublic MainPage(){InitializeComponent();// initializes the PhotoChooserTaskphotoChooserTask = new PhotoChooserTask();photoChooserTask.Completed +=new EventHandler<PhotoResult>(OnPhotoChooserTaskCompleted);}// Launches the photo chooser.private void OnChoosePicture(object sender,System.Windows.Input.GestureEventArgs e){photoChooserTask.Show();}// Called when an existing photo is chosen with the photo chooser.private void OnPhotoChooserTaskCompleted(object sender, PhotoResult e){// Hide text messagestxtError.Visibility = Visibility.Collapsed;txtMessage.Visibility = Visibility.Collapsed;// Make sure the PhotoChooserTask is resurning OKif (e.TaskResult == TaskResult.OK){// initialize the result photo streamphotoStream = new MemoryStream();// Save the stream result (copying the resulting stream)e.ChosenPhoto.CopyTo(photoStream);// save the original file namefileName = e.OriginalFileName;// display the chosen picturevar bitmapImage = new BitmapImage();bitmapImage.SetSource(photoStream);imgSelectedImage.Source = bitmapImage;// enable the upload buttonbtnUpload.IsEnabled = true;}else{// if result is not ok, make sure user can't uploadbtnUpload.IsEnabled = false;}}// calls the UploadFile methodprivate void OnUpload(object sender, System.Windows.Input.GestureEventArgs e){UploadFile();}// uploads the fileprivate async void UploadFile(){try{// Make sure there is a picture selectedif (photoStream != null){// initialize the client// need to make sure the server accepts network IP-based// requests.// ensure correct IP and correct port addressvar fileUploadUrl = @"http://<IPaddress>:<port>/fileupload";var client = new HttpClient();// Reset the photoStream position// If you don't reset the position, the content lenght// sent will be 0photoStream.Position = 0;// This is the postdataMultipartFormDataContent content = new MultipartFormDataContent();content.Add(new StreamContent(photoStream), "file", fileName);// upload the file sending the form info and ensure a result.// it will throw an exception if the service doesn't return// a valid successful status codeawait client.PostAsync(fileUploadUrl, content).ContinueWith((postTask) =>{postTask.Result.EnsureSuccessStatusCode();});}// Disable the Upload buttonbtnUpload.IsEnabled = false;// reset the image controlimgSelectedImage.Source = null;// Display the Uploaded messagetxtMessage.Visibility = Visibility.Visible;}catch{// Display the Uploaded messagetxtError.Visibility = Visibility.Visible;}}}
When the picture is chosen, we want to display it on screen, and then enable the Upload button. We will want to notify the user when the image was successfully upload it, and if there was any error uploading it. Finally, we will clear the image on screen when it is successfully uploaded.
For the upload functionality, I’ll be using a package that allows to use the HttpClient on Windows Phone. To add the required DLLs, open the NuGet Package Manager and search for Microsoft.Net.HttpClient. Install the library on your project.
If you compile the project, you will get an error because of one of the package dependencies, which can only compile for x86 or ARM.
To fix this, just change the target platform to x86 in the configuration manager if you are deploying in the emulator, or ARM if you are deploying on your device.
Although the code is straight forward in terms of functionality, there are a few things to notice that could get you wasting a lot of time trying to solve. You have to pay attention to the way you work with streams. Once you read a stream, the position will change. You have to reset it to “0” when you want to read it again. Then, you need to initialize it if you want to replace it with a new photo stream.
You also need to configure your file upload web service if you want it to work locally. Either the Windows Phone 8 emulator or the device itself will appear as separate devices, so you will need to use your local machine IP address and configure your web server (in my case IIS Express) to accept HTTP requests, and also make sure the Windows Firewall is allowing the private or domain incoming requests on the web service assigned port.
Finally, you have to control the exception thrown by the HttpClient post task if the request is not successful. Remember that if you want to modify the UI from the request task, you will need to use a dispatcher, since the request is running on a non-UI thread.
Here are some screenshots of the running app. I tested the code running both in the Windows Phone 8 emulator and on the actual device.
Special thanks to my colleague Herber Madrigal who was kind enough to put together the initial proof of concept and point me into the right direction.
Make sure to read my initial post on how to implement the File Upload Web Service, and then afterwards, make sure to check my post on how to enable the Windows Phone 8 Emulator and your network devices to connect to your local web services. Without this, you won’t be able to test and debug your apps and services locally!
Finally, you can grab the complete sample code for the WP8 File Upload from my Github repo here.
great post !
ReplyDelete