(X) Hide this
    • Login
    • Join
      • Generate New Image
        By clicking 'Register' you accept the terms of use .

Background processing in Windows 8: Part 5: Background transfers in Windows 8

(3 votes)
Gill Cleeren
>
Gill Cleeren
Joined Apr 02, 2010
Articles:   63
Comments:   6
More Articles
4 comments   /   posted on Jun 13, 2013
Tags:   windows-8 , gill-cleeren
Categories:   Windows 8

Tweet

Welcome to part 5 of this series on background processing in Windows 8 applications. In this part, we are going to explore an option to transfer files in the background. With the specifics that surround the process lifecycle of Windows 8, downloading or uploading a file in a Windows app isn’t possible without a specific option in the framework. This option is often referred to as the Background Transfer API. This API is the focus of this article.

The need for the Background Transfer API

In part 1 of this series, we have covered the process lifecycle of Windows 8 Store apps. If you remember correctly, by default only one Windows 8 app can be running in the foreground. When the app isn’t running in the foreground any longer, the app will be suspended (after 5 seconds). If you’re building an app that has to transfer files (upload or download), your transfer will be suspended so you’re basically locking the user in your application as long as the transfer in running. I don’t think a lot of users will be happy with this experience!

The solution for this problem is the Background Transfer API. Using this API, it becomes possible to allow apps to register transfers with a separate service.

The API explained

The API allows us to register downloads or uploads with a separate service instead of allowing the transfer to happen from your application. When using this API, you’ll see a separate service being created, running as a separate process, as can be seen in the image below. The process is named after the name of the application performing the transfer.

clip_image002

However, if we take a look at the details, we can see that in fact the process is called BackgroundTransferHost.exe. An instance of this exe is created for each application that performs a download or upload.

clip_image004

Thanks for this service, the download won’t be suspended when the application is going into suspended mode. Indeed, I’m saying here Suspended mode. The process won’t be interrupted if the application is suspended but it will be killed if the application gets terminated, even if it’s being terminated because of memory reasons. Therefore, when the device reboots, the download is cancelled as well. The same goes for an application crash. For the Windows Phone developers among us, this may come as a surprise. WP has a similar mechanism to allow downloading outside of the application. But in WP, the downloads “survive” device reboots.

All classes that have to do with the Background Transfer API are living in the Windows.Networking.BackgroundTransfer namespace. The most relevant class for downloading is the BackgroundDownloader class (for uploading, you can probably guess it is the BackgroundUploader class). These classes support transferring files over http and https. The BackgroundDownloader also support ftp tranfers.

Downloading a file

Let’s take a look at how we can download a file using the BackgroundDownloader class. If we think about a download, it’s basically defined by 2 things: the file we want to download and the file we want to create locally. In the sample application, we can specify the file we want to download, as can be seen below.

clip_image006

In code, we’ll create a file on the local disk. We can use the following code to create a file name from the URI:

   1: private string CreateFileName(Uri uri)
   2: {
   3:     return Path.GetFileName(uri.LocalPath);
   4: }

Once we have the file name, we can create the download. A download is defined by a DownloadOperation instance. We can create an instance of this class as follows:

   1: private async Task<DownloadOperation> CreateDownload(Uri uri, string fileName)
   2: {
   3:     StorageFile storageFile = await 
   4:         KnownFolders.VideosLibrary.CreateFileAsync(fileName, CreationCollisionOption.GenerateUniqueName);    
   5:     BackgroundDownloader downloader = new BackgroundDownloader();
   6:  
   7:     downloader.CostPolicy = BackgroundTransferCostPolicy.UnrestrictedOnly;
   8:  
   9:     return downloader.CreateDownload(uri, storageFile);
  10:  
  11: }

In the code above, I’m using the CreateFileAsync() method, passing in the file name and the location. This StorageFile instance is not a physical file, it’s merely a representation of a file. Note that this is an async operation of course, since it involves IO. Next, we instantiate the BackgroundDownloader class and call on to the CreateDownload(), passing in the file we want to download and the StorageFile (in other words, where to put the file). This call returns us a DownloadOperation. The download hasn’t started yet at this point though.

To start the actual download of the file, we call on to the StartAsync of the DownloadOperation as follows:

   1: var download = await CreateDownload(uri, fileName);
   2:  
   3: await download.StartAsync()
   4:     .AsTask(cancellationTokenSource.Token, downloadProgressCallback);

Note that we are calling the AsTask(), passing in 2 more parameters. AsTask returns a Task that represents the ongoing operation.

The first parameter, cancellationTokenSource.Token, gets the Token associated with the CancellationTokenSource. Uhm, what? Well, to put it simple, it’s possible to cancel a download. However, a download happens async. To cancel an async task, we use the CancellationTokenSource.Token, which allows us to signal that the (or better: all) async tasks associated with this token, should be cancelled. To actually cancel a download, we can use the following code:

   1: private void CancelAllDownloadsButton_Click_1(object sender, RoutedEventArgs e)
   2: {
   3:     cancellationTokenSource.Cancel();
   4:     cancellationTokenSource.Dispose();
   5:  
   6:     cancellationTokenSource = new CancellationTokenSource();
   7: }

The second parameter, downloadProgressCallback, is defined as follows;

   1: Progress<DownloadOperation> downloadProgressCallback = 
   2:     new Progress<DownloadOperation>(UpdateDownloadProgress1);

This provides an IProgress<T>, that will invoke the callback (UpdateDownloadProgress1) every time progress is being reported. So basically, this allows us to specify what needs to happen when there progress being reported from the transfer. In our case, we are updating a progress bar in the UI.

   1: private void UpdateDownloadProgress1(DownloadOperation downloadOperation)
   2: {
   3:     if (downloadOperation.Progress.TotalBytesToReceive > 0)
   4:     {
   5:         var ignore = this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
   6:             {
   7:                 DownloadProgressBar1.Value = 
   8:                     downloadOperation.Progress.BytesReceived * 100 
   9:                         / downloadOperation.Progress.TotalBytesToReceive;
  10:             });
  11:      }
  12:  
  13: }

Since this code runs in a background thread, you will need to use the Dispatcher to update UI elements, as can be seen above. It’s of course required that the main application is running in the foreground, otherwise we can’t update the UI since the app wouldn’t be getting any CPU assigned to it. If the main app isn’t in the foreground, this code will simply have no effect; in other words, you won’t get any error or have to add any checks to see if the main app is effectively in the foreground.

With this code, we can download a file from any URI to the local storage of the Windows 8 application. Even if the application enters suspended mode, the download will continue.

But as mentioned, when the application is terminated, the download will not continue, since the separate process is being terminated as well. However, it would be a good experience for the user that all what had been downloaded so far isn’t gone (remember that the default experience in Windows 8 is that the user should not be aware that the application is being terminated; the app should try to restore all state). This is possible, let’s take a look at how we can do that next.

First, we need to retrieve the “paused” downloads. We can do that using the BackgroundDownloader class again which defines a GetCurrentDownloadsAsync() method. Once we have this List<DownloadOperation> (which is the return type of this class), for each DownloadOperation, we call the AttachAsync() method. This method will resume the download. Since this is async, we can loop over all paused downloads and start them all together in one go. The result is concurrent downloads running within the application.

   1: private async Task RetrieveActiveDownloads()
   2: {
   3:     try
   4:     {
   5:         List<Task> downloadTasks = new List<Task>();
   6:  
   7:         var downloads = await BackgroundDownloader.GetCurrentDownloadsAsync();
   8:  
   9:         foreach (var download in downloads)
  10:         {
  11:             downloadTasks.Add(ResumeDownload(download));
  12:         }
  13:  
  14:         await Task.WhenAll(downloadTasks);
  15:     }
  16:     catch (Exception)
  17:     { }
  18: }
  19:  
  20: private async Task ResumeDownload(DownloadOperation downloadOperation)
  21:  
  22: {
  23:  
  24: Progress<DownloadOperation> downloadProgressCallback = 
  25:  
  26: new Progress<DownloadOperation>(ResumeDownloadProgress);
  27:  
  28: await downloadOperation.AttachAsync()
  29:  
  30: .AsTask(cancellationTokenSource.Token, downloadProgressCallback);
  31:  
  32: }

If we execute this code, we can see that we have multiple downloads happening at the same time.

clip_image008

To finish this article, let’s take a look at uploading files.

Uploading a single file

Uploading a file has the same “issues” as downloading a file: when the application gets suspended, the upload that we do from the application itself will get cancelled. Instead, we have to use the separate process here too. To upload, we are going to use the BackgroundUploader class, and we can use the CreateUpload() method on the BackgroundUploader to create an UploadOperation. On the UploadOperation, we can then call the StartAsync() to start the upload. Uploads too can be cancelled and can report progress in the exact same way as we saw with with downloading.

The code below performs an upload. Note that we can also use the SetRequestHeader to pass/set specific headers in the request. We can also pass credentials if needed using the ServerCredential property. This was also possible with the BackgroundDownloader.

   1: Progress<UploadOperation> uploadProgressCallback = 
   2:     new Progress<UploadOperation>(UploadProgress);
   3:    
   4: BackgroundUploader backgroundUploader = new BackgroundUploader();
   5: backgroundUploader.SetRequestHeader("Filename", selectedFile.Name);
   6:  
   7: var uploadOperation = 
   8:     backgroundUploader.CreateUpload
   9:         (new Uri("http://posttestserver.com/post.php", UriKind.Absolute), selectedFile);
  10:  
  11: var result = await uploadOperation.StartAsync()
  12:     .AsTask(uploadCancellationTokenSource.Token, uploadProgressCallback);

It’s also possible to upload more than one file in just one upload operation. The file to-be-uploaded are then placed in a list and all these files will be uploaded after one another. For this, we have the BackgroundTransferContentPart class. For each file we want to upload, we are going to create such an instance. We then pass this list of BackgroundTransferContentPart instances to the BackgroundUploader. This is shown in the code below.

   1: var selectedFiles = await picker.PickMultipleFilesAsync();
   2:  
   3: if (selectedFiles != null)
   4: {
   5:     var parts = new List<BackgroundTransferContentPart>();
   6:  
   7:     foreach (var file in selectedFiles) 
   8:     {
   9:         var part = new BackgroundTransferContentPart();
  10:         part.SetFile(file);
  11:         parts.Add(part);
  12:     }
  13:  
  14:     Progress<UploadOperation> uploadProgressCallback = 
  15:         new Progress<UploadOperation>(UploadProgress);
  16:  
  17:     BackgroundUploader backgroundUploader = new BackgroundUploader();
  18:  
  19:     var uploadOperation = await backgroundUploader.CreateUploadAsync
  20:         (new Uri("http://posttestserver.com/post.php", UriKind.Absolute), parts);
  21:  
  22:     var result = await uploadOperation.StartAsync()
  23:         .AsTask(uploadCancellationTokenSource.Token, uploadProgressCallback);
  24: }

Summary

In this part, we’ve extensively covered the Background Transfer API to allow our apps to upload and download files while not the main application on screen. This way, we improve the user experience: the user can do other stuff while the download is taking place.

In the 6th and final part, we will look at playing audio from the background. Hope to see you there!

About the author

Gill Cleeren is Microsoft Regional Director, Silverlight MVP, Pluralsight trainer and Telerik MVP. He lives in Belgium where he works as .NET architect at Ordina. Gill has given many sessions, webcasts and trainings on new as well as existing technologies, such as Silverlight, ASP.NET and WPF at conferences including TechEd, TechDays, DevDays, NDC Oslo, SQL Server Saturday Switserland, Silverlight Roadshow in Sweden, Telerik RoadShow UK… Gill has written 2 books: “Silverlight 4 Data and Services Cookbook” and Silverlight 5 Data and Services Cookbook and is author of many articles for magazines and websites. You can find his blog at www.snowball.be. Twitter: @gillcleeren


Subscribe

Comments

  • BenGeerdes

    Re: Background processing in Windows 8: Part 5: Background transfers in Windows 8


    posted by BenGeerdes on Jun 15, 2013 18:16

    Now this is specific for up/downloading files. What if I have a WCF service to up/download information, can I create my own implementation of DownloadOperation etc, that basically encapsulates the WCF process? Reason I ask is when you have a WCF service for up/download info, when a RT app has nothing to do (while another thread is running the WCF up/down_, it goes to sleep, and breaks the WCF process. If the WCF process could be run as a Background up/down - load, it would continue ebven if the app ges to sleep.



  • SureshPokkuluri

    Re: Background processing in Windows 8: Part 5: Background transfers in Windows 8


    posted by SureshPokkuluri on Jun 17, 2013 01:45

    I too have similar question as Ben asked. Can I use background transfer API to call my WCF or Web API service to get JSON file to the client? I want to get that JSON from the service and I want to store the data in app's SQLite DB. is it possible with background transfer API?

    Also, I want to use this background transfer API in a background task and want to register it with time trigger so that user no need to initiate the process every time. By the time user opens the app, he will see latest information/data (as background transfer API executed periodically in BG Task). Is it something possible to achieve?

    Thanks for answering in advance!

  • syifa

    Re: Background processing in Windows 8: Part 5: Background transfers in Windows 8


    posted by syifa on Jun 22, 2013 12:13

    hello . please help me .

    how do we know that the download and upload was successful

    and where can be seen the result of download and upload ?

     thank you

  • angelredes

    Re: Background processing in Windows 8: Part 5: Background transfers in Windows 8


    posted by angelredes on Feb 06, 2014 08:48

    how to restore upload file Background Transfer API network status changes ConnectionReset (BackgroundUploader  -- UploadOperation)

    UploadOperation does it automatically?

Add Comment

Login to comment:
  *      *       

From this series