How to upload a file (HTML)
[This article is for Windows 8.x and Windows Phone 8.x developers writing Windows Runtime apps. If you’re developing for Windows 10, see the latest documentation]
This topic will show you how to upload data or a file from a device to the Internet.
Apps can use the APIs discussed in this topic to enable their app to interact with web services to consume or share popular media formats like photos, music, and video.
For large, stream-based, or multi-part transfers (video, music, and large images), with an operational lifetime that may span beyond multiple app suspensions and/or changes in network availability, your app can use Background Transfer.
For a high-level look at Background Transfer, see Transferring data in the background.
Prerequisites
For general help creating a JavaScript Windows Store app, see Create your first Windows Runtime app using JavaScript. Additionally, JavaScript promises are used in this topic to complete asynchronous operations. For more information on this programming pattern, see Asynchronous programming in JavaScript using promises.
To ensure your app is network ready, you must set the capability in the project Package.appxmanifest file. For a definition of each network capability, see How to configure network isolation capabilities.
The following Background Transfer examples use JavaScript and are based on the Background Transfer sample.
Background Transfer Upload Operations
When using Background Transfer an upload exists as an UploadOperation that exposes a number of control methods that are used to restart or cancel the operation. App events (e.g. suspension or termination) and connectivity changes are handled automatically by the system per UploadOperation; uploads will continue during app suspension periods or pause and persist beyond app termination. Additionally, setting the CostPolicy property will indicate whether or not your app will start uploads while a metered network is being used for Internet connectivity.
The following examples will walk you through the creation and initialization of a basic upload and how to enumerate and reintroduce operations persisted from a previous app session.
Upload a file
The creation of an upload begins with BackgroundUploader. This class is used to provide the methods that enable your app to configure the upload before creating the resultant UploadOperation. The following example shows how to do this with the required Uri and StorageFile objects.
Identify the file and destination for the upload
Before we can begin with the creation of an UploadOperation, we first need to identify the URI of the location to upload to, and the file that will be uploaded. In the following example, the uriString value is populated using a string from UI input, and the file value using the StorageFile object returned by a PickSingleFileAsync operation.
function uploadFile() { var filePicker = new Windows.Storage.Pickers.FileOpenPicker(); filePicker.fileTypeFilter.replaceAll(["*"]); filePicker.pickSingleFileAsync().then(function (file) { if (!file) { printLog("No file selected"); return; } var upload = new UploadOp(); var uriString = document.getElementById("serverAddressField").value; upload.start(uriString, file); // Store the upload operation in the uploadOps array. uploadOperations.push(upload); }); }
Create and initialize the upload operation
In the previous step the uriString and file values are passed to an instance of our next example, UploadOp, where they are used to configure and start the new upload operation. First, uriString is parsed to create the required Uri object.
Next, the properties of the provided StorageFile (file) are used by BackgroundUploader to populate the request header and set the SourceFile property with the StorageFile object. The SetRequestHeader method is then called to insert the file name, provided as a string, and the StorageFile.Name property.
Finally, BackgroundUploader creates the UploadOperation (upload).
function UploadOp() { var upload = null; var promise = null; this.start = function (uriString, file) { try { var uri = new Windows.Foundation.Uri(uriString); var uploader = new Windows.Networking.BackgroundTransfer.BackgroundUploader(); // Set a header, so the server can save the file (this is specific to the sample server). uploader.setRequestHeader("Filename", file.name); // Create a new upload operation. upload = uploader.createUpload(uri, file); // Start the upload and persist the promise to be able to cancel the upload. promise = upload.startAsync().then(complete, error, progress); } catch (err) { displayError(err); } }; // On application activation, reassign callbacks for a upload // operation persisted from previous application state. this.load = function (loadedUpload) { try { upload = loadedUpload; promise = upload.attachAsync().then(complete, error, progress); } catch (err) { displayError(err); } }; }
Note the asynchronous method calls defined using JavaScript promises. Looking at a line from the last example:
promise = upload.startAsync().then(complete, error, progress);
The async method call is followed by a then statement which indicates methods, defined by the app, that are called when a result from the async method call is returned. For more information on this programming pattern, see Asynchronous programming in JavaScript using promises.
Upload multiple files
Identify the files and destination for the upload
In a scenario involving multiple files transferred with a single UploadOperation, the process begins as it usually does by first providing the required destination URI and local file information. Similar to the example in the previous section, the URI is provided as a string by the end-user and FileOpenPicker can be used to provide the ability to indicate files through the user interface as well. However, in this scenario the app should instead call the PickMultipleFilesAsync method to enable the selection of multiple files through the UI.
function uploadFiles() { var filePicker = new Windows.Storage.Pickers.FileOpenPicker(); filePicker.fileTypeFilter.replaceAll(["*"]); filePicker.pickMultipleFilesAsync().then(function (files) { if (files === 0) { printLog("No file selected"); return; } var upload = new UploadOperation(); var uriString = document.getElementById("serverAddressField").value; upload.startMultipart(uriString, files); // Persist the upload operation in the global array. uploadOperations.push(upload); }); }
Create objects for the provided parameters
The next two examples use code contained in a single example method, startMultipart, which was called at the end of the last step. For the purpose of instruction the code in the method that creates an array of BackgroundTransferContentPart objects has been split from the code that creates the resultant UploadOperation.
First, the URI string provided by the user is initialized as a Uri. Next, the array of IStorageFile objects (files) passed to this method is iterated through, each object is used to create a new BackgroundTransferContentPart object which is then placed in the contentParts array.
upload.startMultipart = function (uriString, files) { try { var uri = new Windows.Foundation.Uri(uriString); var uploader = new Windows.Networking.BackgroundTransfer.BackgroundUploader(); var contentParts = []; files.forEach(function (file, index) { var part = new Windows.Networking.BackgroundTransfer.BackgroundTransferContentPart("File" + index, file.name); part.setFile(file); contentParts.push(part); });
Create and initialize the multi-part upload operation
With our contentParts array populated with all of the BackgroundTransferContentPart objects representing each IStorageFile for upload, we are ready to call CreateUploadAsync using the Uri to indicate where the request will be sent.
// Create a new upload operation. uploader.createUploadAsync(uri, contentParts).then(function (uploadOperation) { // Start the upload and persist the promise to be able to cancel the upload. upload = uploadOperation; promise = uploadOperation.startAsync().then(complete, error, progress); }); } catch (err) { displayError(err); } };
Enumerate persisted operations at start-up
On completion or cancellation of an UploadOperation, any associated system resources are released. However, if your app is terminated before either of these things can occur, any active operations are paused and the resources associated with each remain occupied. If these operations are not enumerated and re-introduced to the next app session, they will not be completed and will continue to occupy device resources.
Before defining the function that enumerates persisted operations, we need to create an array that will contain the UploadOperation objects that it will return:
var uploadOperations = [];
Next we define the function that enumerates persisted operations and stores them in our array. Note that the load method called to re-assign callbacks to the UploadOperation, should it persist through app termination, is in the UploadOp class we define later in this section.
function Windows.Networking.BackgroundTransfer.BackgroundUploader.getCurrentUploadsAsync() { .then(function (uploads) { for (var i = 0; i < uploads.size; i++) { var upload = new UploadOp(); upload.load(uploads[i]); uploadOperations.push(upload); } } };
Note
For Windows Phone Store apps, background transfers continue to progress while your app is not in the foreground. Because your app is not running in this scenario, it will not receive a notification when the transfer completes. When your app resumes, if you just check the progress of a completed transfer, the status will be BackgroundTransferStatus.Running. However, when you attach to the transfer as in the example code above, the task completion handler will be raised and the transfer status will be updated.
Request Timeouts
There are two primary connection timeout scenarios to take into consideration:
When establishing a new connection for a transfer, the connection request is aborted if it is not established within five minutes.
After a connection has been established, an HTTP request message that has not received a response within two minutes is aborted.
Note In either scenario, assuming there is Internet connectivity, Background Transfer will retry a request up to three times automatically. In the event Internet connectivity is not detected, additional requests will wait until it is.
Debugging Guidance
Stopping a debugging session in Microsoft Visual Studio is comparable to closing your app; PUT uploads are paused and POST uploads are terminated. Even while debugging, your app should enumerate and then restart or cancel any persisted uploads. For example, you can have your app cancel enumerated persisted upload operations at app startup if there is no interest in previous operations for that debug session.
While enumerating downloads/uploads on app startup during a debug session, you can have your app cancel them if there is no interest in previous operations for that debug session. Note that if there are Visual Studio project updates, like changes to the app manifest, and the app is uninstalled and re-deployed, GetCurrentUploadsAsync cannot enumerate operations created using the previous app deployment.
See Debugging and testing Windows Store apps for more information.
When using Background Transfer during development, you may get into a situation where the internal caches of active and completed transfer operations can get out of sync. This may result in the inability to start new transfer operations or interact with existing operations and BackgroundTransferGroup objects. In some cases, attempting to interact with existing operations may trigger a crash. This result can occur if the TransferBehavior property is set to Parallel. This issue occurs only in certain scenarios during development and is not applicable to end users of your app.
Four scenarios using Visual Studio can cause this issue.
- You create a new project with the same app name as an existing project, but a different language (from C++ to C#, for example).
- You change the target architecture (from x86 to x64, for example) in an existing project.
- You change the culture (from neutral to en-US, for example) in an existing project.
- You add or remove a capability in the package manifest (adding Enterprise Authentication, for example) in an existing project.
Regular app servicing, including manifest updates which add or remove capabilities, do not trigger this issue on end user deployments of your app.
To work around this issue, completely uninstall all versions of the app and re-deploy with the new language, architecture, culture, or capability. This can be done via the Start screen or using PowerShell and the Remove-AppxPackage cmdlet.
Summary and next steps
In this topic we reviewed how to upload files using the Background Transfer APIs in JavaScript.
You can also download files in your Windows Store app. For an explanation of core concepts and examples, see How to download a file.
Related topics
Other
Accessing connection and data plan information
Asynchronous programming in JavaScript using promises
Create your first Windows Runtime app using JavaScript
How to configure network capabilities
How to download a file with WinJS xhr
Reference
Windows.Networking.BackgroundTransfer
Samples