Jump to content

Migrating your Windows Phone app from the Background Transfer Service to the converged...


Recommended Posts

Guest Windows Apps Team
Posted

This blog was written by Himadri Sarkar, Program Manager, Windows Networking

 

Starting with Windows Phone 8.1, you can call the Windows Runtime API for background file transfers from Windows Phone Silverlight 8.1 based applications. In this post, I’ll introduce you to that API and the reasons why you’ll want to migrate your Windows Phone app to use it.

One of the most common cases in which you want your apps to run in the background is to perform a large file transfer to or from the cloud. Since Windows Phone 7.1, the Windows Phone operating system has provided the background transfer service (BTS) for this purpose. (The BTS API is in the Microsoft.Phone.BackgroundTransfer namespace.) But with Windows Phone 8.1 you can now use the Windows Runtime API in Windows.Networking.BackgroundTransfer, which I’ll refer to in this post as BT. The BT API, along with the convergence of most of the Windows Runtime API, significantly reduces the development cost of a universal app that targets both Windows and Windows Phone. (The BT API is also the only background-transfer option available for Windows Phone apps written with HTML, CSS, and JavaScript.)

In addition, the BT API delivers a number of features that developers have been asking for in BTS:

No arbitrary file-size restrictions: BTS restricts transfer file sizes based on the network conditions (details here). In BT there are no file-size restrictions; it’s bound only by the amount of free space available on the phone’s internal storage.

  • Support for additional HTTP verbs: BT supports the use of additional HTTP verbs: PUT, RETR, and STOR. It also supports FTP as a transfer option.
  • Access to the stream during download: BT provides a method (GetResultStreamAt) to access the stream while it is being downloaded. This feature is not available in BTS.
  • Multi-part mime support: BT supports multi-part transfers (see the BackgroundTransferContentPart class), which BTS does not.
  • Tile and toast notifications: With BT, developers can specify tile updates and toast notifications to be issued when the transfer is complete or when an error occurs.
  • Grouping and other options: BT supports the concept of transfer groups, and parallel and serial transfer options, which can be used to group a set of transfers as a unit.

 

Clearly there are many advantages to migrating from the BTS API to the BT API. Hopefully at least one of the features above has piqued your interest.

But if you’ve already built core functionality of your app on BTS, you likely have two key questions:

  • Is BT available for Silverlight apps? The answer is simple: yes! Any Silverlight app updated to target Windows Phone 8.1 can use BT.
  • How you can transition your code from using BTS to using BT? For the answer to that question, continue reading!

 

In the rest of this post, I’ll highlight the key differences between BTS and BT, using code snippets from a real app to illustrate the changes required to complete the migration.

We’ll begin with the Background Transfer Service sample for Windows Phone 8.0Background Transfer Service sample for Windows Phone 8.0, which covers the core functionality of BTS. The first step is to migrate the project to Windows Phone 8.1. Open the project in Microsoft Visual Studio 2013 and retarget to Windows Phone 8.1.

Architectural background

 

 

Before getting into the details of the migration, let’s take a look at some of the architectural differences between the two APIs. As the name implies, the Windows Phone Background Transfer Service (BTS) is a system-provided service that manages uploads and downloads on behalf of your app. That service in turn uses another and more primitive service, known as the Entertainment Download Manager (EDM), to actually perform the necessary HTTP operations. The EDM is used for most background file transfers on the phone, including the download of apps from the Store. It is called the Entertainment Download Manager because it was initially designed to handle download of content such as music and videos.

The Windows Runtime BackgroundTransfer (BT) API, on the other hand, is based on the background task infrastructure used for all app-driven background processing in the Windows app model. When an app queues a transfer by using the BT API, the system spawns a background task to complete the transfer. This background task runs within the app container but is hosted and managed separately from the foreground app instance. As a result, transfers proceed regardless of whether the app is running, suspended, or has been explicitly closed. The background task infrastructure also takes care of pausing and resuming tasks in various conditions, like when battery saver is turned on or when the network cost changes.

Migration focus areas

 

 

When you migrate from BTS to BT, there are a number of details to keep in mind.

First is the treatment of upload and download requests. BTS has a single BackgroundTransferRequest class to handle both uploads and downloads. BT, on the other hand, has separate classes for uploads and downloads: UploadOperationUploadOperation and DownloadOperationDownloadOperation.

Next, in BTS the methodology is to build the BackgroundTransferRequest object first and then queue it by using the BackgroundTransferService object. In BT, we instead start by creating the BackgroundDownloader and BackgroundUploader objects, which are logical (albeit non-static) equivalents of the BTS BackgroundTransferService class. We then use those objects to create and queue the transfer requests.

Finally, while both BTS and BT support progress updates as the transfer proceeds, we must register for those updates differently. BTS reports progress via a set of specific events that your app must register for on the BackgroundTransferRequest class. As a Windows Runtime API, BT relies on the asynchronous task model and reports progress to an instance of IProgress<T>. As a result, we need to create a progress handler and attach it when starting a transfer.

To put things in perspective, here’s the task-creation code for each API, one after the other to help you compare.

 

BTS

 

 

//Creation of the URI from which

//the download needs to happen.

Uri transferUri = new Uri(Uri.EscapeUriString(transferFileName), UriKind.RelativeOrAbsolute);

 

//Creation of the download request.

BackgroundTransferRequest transferRequest = new BackgroundTransferRequest(transferUri);

 

//Set the HTTP method of the request.

transferRequest.Method = "GET";

 

//Get the file name from the end of

//the transfer Uri and create a local Uri

//in the "transfers" directory in isolated storage.

string downloadFile = transferFileName.Substring(transferFileName.LastIndexOf("/") + 1);

Uri downloadUri = new Uri("shared/transfers/" + downloadFile, UriKind.RelativeOrAbsolute);

transferRequest.DownloadLocation = downloadUri;

 

//Schedule the request.

BackgroundTransferService.Add(transferRequest);

 

//For BTS, we need to handle transfer status

//and transfer progress through event handlers.

transfer.TransferStatusChanged += new EventHandler<BackgroundTransferEventArgs>(transfer_TransferStatusChanged);

 

transfer.TransferProgressChanged += new EventHandler<BackgroundTransferEventArgs>(transfer_TransferProgressChanged);

 

 

BT

 

 

//Creation of the URI from which

//the download needs to happen.

Uri transferUri = new Uri(Uri.EscapeUriString(transferFileName), UriKind.RelativeOrAbsolute);

 

//Create the file where the download

//will happen.

string downloadFile = transferFileName.Substring(transferFileName.LastIndexOf("/") + 1);

StorageFile downloadedFile = await KnownFolders.PicturesLibrary.CreateFileAsync(downloadFile);

 

//First create the downloader object.

BackgroundDownloader downloader = new BackgroundDownloader();

 

//Then create a downloadoperation

//using the downloader.

DownloadOperation downloadoperation = downloader.CreateDownload(transferUri,downloadedFile);

 

//Set the HTTP method of the request

//on the downloader.

downloader.Method = "GET";

 

//Assign a progress handler

//callback function to the download.

Progress<DownloadOperation> progresscallback = new Progress<DownloadOperation>(DownloadProgress);

 

//Schedule the request.

await downloadoperation.StartAsync().AsTask(cts.Token, progresscallback);

 

File-handling differences

 

 

It’s worth pointing out a few key differences in the way that BTS and BT deal with files. First, as noted earlier, BT does not restrict transfer size like BTS does, although there are limits in BT that are governed by the following factors:

  • Amount of storage space available on the device as a whole.
  • Network connection cost (cellular vs. Wi-Fi)—BT is integrated with Data Sense, so if cellular is the only available connection, transfers are limited by the data plan. Beyond this limit, the transfer is paused and waits for a non-metered (Wi-Fi) network.
  • Power condition (battery vs. AC power)—When the device is on AC power, there is no limit on transfer size. When the device is on battery power, transfer size is restricted on an internal, time-based quota. If the transfer exceeds the quota, it’s paused until the quota is reset.

 

Second, BTS requires that files be placed within the shared/transfers/ folder (or any subfolder thereof) of the app’s isolated storage. BT instead uses StorageFile objects to reference files, making it very flexible in terms of where files can reside. A file can be in your app’s local storage, in one of the user libraries (pictures, music, or videos), or on the SD card.

Transfer-preference and cost-policy differences

 

 

Both the BTS and BT APIs allow your app to control when the transfer should be scheduled, by means of system-defined enumerations: TransferPreferences for BTS and BackgroundTransferCostPolicy for BT. Here are the available values in each enumeration.

TransferPreferences options (BTS)

 

 

Value

 

 

Description

 

 

None

 

 

Allow transfers only when the device is using external power and has a Wi-Fi connection. This is the default setting.

 

 

AllowCellular

 

 

Allow transfers when the device is connected to external power and has a Wi-Fi or cellular connection.

 

 

AllowBattery

 

 

Allow transfers when there is a Wi-Fi connection and the device is using battery or external power.

 

 

AllowCellularAndBattery

 

 

Allow transfers when the device is using battery or external power and has a Wi-Fi or cellular connection.

 

BackgroundTransferCostPolicy options (BT)

 

 

Value

 

 

Description

 

 

Default

 

 

Allow transfers on metered networks.

 

 

UnrestrictedOnly

 

 

Do not allow transfers on metered networks.

 

 

Always

 

 

Always download regardless of network cost (for example, even while a user is roaming).

 

 

Here are the key differences:

  • BTS requires your apps to govern both power and network policies. BT asks apps to control only the network cost because the operating system manages all power policies automatically. So if your UI provides an option like “Download only on Wi-Fi and AC Power,” you’ll now want to have it say just “Download only on Wi-Fi”, because that’s the only option that your app can control directly.
  • BT allows your app to specify network cost rather than network type. In effect, network cost acts as an abstraction over network type and recognizes that, while cellular networks are usually metered and Wi-Fi networks are usually free, neither assumption is guaranteed. As a result, there is no way to explicitly specify that a transfer should be “Wi-Fi only” when using BT. Instead, your app should use the UnrestrictedOnly option, which ensures that transfers won’t proceed if the user’s device has only a metered connection. But if the user has an unlimited data plan, her cellular connection will be considered unrestricted and downloads will proceed when it is available. (To avoid user confusion, then, you may want to consider changing UI options that refer to “Wi-Fi only” to something more general.
  • The default cost option for BT is less restrictive and can transfer over cellular networks, but it is governed by the Data Sense policies.

 

The following table describes the BackgroundTransferCostPolicy enumeration options for BT and their behavior in different network conditions.

 

 

Scenario

 

 

UnrestrictedOnly

 

 

Default

 

 

Always

 

 

Wi-Fi

 

 

Allow

 

 

Allow

 

 

Allow

 

 

Metered connection, not roaming, under data limit, on track to stay under limit

 

 

Deny

 

 

Allow

 

 

Allow

 

 

Metered connection, not roaming, under data limit, on track to exceed limit

 

 

Deny

 

 

Deny

 

 

Allow

 

 

Metered connection, roaming, under data limit

 

 

Deny

 

 

Deny

 

 

Allow

 

 

Metered connection, over data limit. This state only occurs when the user enables "Restrict background data in the Data Sense UI.

 

 

Deny

 

 

Deny

 

 

Deny

 

 

Accessing the list of transfers, handling progress, and checking status

 

 

Once transfers have been created and queued, you usually want to keep track of them and get status updates. Again, there are a handful of differences between BTS and BT to keep in mind:

  • BTS limits the total number of active and pending requests to 25, forcing your app to actively manage its own queue. BT has no limit, so you can remove such code from your app altogether. (Be sure, though, to check for success or failure of a new request, because BT does enforce an overall system limit of 1,000 requests).
  • BT supports the concept of grouping of transfers. You can create a named group (using the BackgroundTransferGroup class) and use it to associate multiple download or upload operations with each other. Also you can define whether the transfers in a group can proceed simultaneously or serially, or based on priority by using the BackgroundTransferBehavior and BackgroundTransferPriority enumerations.
  • In BTS, you query the list of queued transfers via a read-only property of BackgroundTransferService, called Requests. In BT, you call GetCurrentDownLoadsAsync and GetCurrentDownloadsForTransferGroupAsync.
  • In BTS you can find a specific transfer via the BackgroundTransferService.Find method. In BT, you instead iterate through the list of DownloadOperations or UploadOperations objects and look for the GUID of the specific transfer.
  • Here are the major differences in progress handling between these two APIs:
    • As mentioned earlier, the handling of BTS transfers is event driven, whereas the BT infrastructure is based on asynchronous tasks, so your progress-handling code must be rewritten to migrate from BTS to BT. Here’s a simple, side-by-side example of progress handling with each API.

 

BTS

 

 

//Get the transfer requests from

//the BackgroundTransferservice’s request

//property.

IEnumerable<BackgroundTransferRequest> transferRequests;

transferRequests = BackgroundTransferService.Requests;

 

//Iterate through all the requests and

//add an event handler to each of them.

foreach (var transfer in transferRequests)

{

transfer.TransferStatusChanged += new EventHandler<BackgroundTransferEventArgs>(transfer_TransferStatusChanged);

transfer.TransferProgressChanged += new EventHandler<BackgroundTransferEventArgs>(transfer_TransferProgressChanged);

}

 

//Process the transfer’s status in the event handler.

void transfer_TransferStatusChanged(object sender, BackgroundTransferEventArgs e)

{

ProcessTransfer(e.Request);

UpdateUI();

}

 

BT

 

//Get the transfer requests using the

//GetCurrentDownloadsAsync call on the

//BackgroundDownloader instance.

IReadOnlyList<DownloadOperation> transferRequests;

List<Task> tasks;

 

//Iterate through all the requests.

foreach (var transfer in transferRequests)

{

//For BT we control the transfers via

//tasks. ProcessTransfer is the task code

//that will run during the progress

//callback.

tasks.Add(ProcessTransfer(transfer));

}

 

As you’ll see in the next two tables, the TransferStatus enumeration in BTS and the BackgroundTransferStatus enumeration in BT have a lot in common. I’ve also included a third table to show suggested mapping between the two enumerations. However, it’s important to note that not all states in BTS can be mapped to a specific BackgroundTransferStatus state in BT.

 

 

 

 

BT BackgroundTransferStatus value

 

 

Description

 

 

Idle

 

 

The app is idle.

 

 

Running

 

 

The transfer is currently in progress.

 

 

PausedByApplication

 

 

The app has paused the transfer operation.

 

 

PausedCostedNetwork

 

 

The transfer operation is paused due to cost policy (for example, the active network transitioned to a costed network).

 

 

PausedNoNetwork

 

 

The transfer operation is paused due to a lack of network connectivity.

 

 

PausedSystemPolicy

 

 

The transfer operation is paused due to resources not being available or 2G network condition or the device got into battery saver mode.

 

 

Completed

 

 

The transfer operation is complete.

 

 

Canceled

 

 

The transfer operation has been canceled.

 

 

Error

 

 

An error was encountered during the transfer operation.

 

 

 

BTS TransferStatus value

 

 

Description

 

 

None

 

 

The request has not yet been queued.

 

 

Transferring

 

 

The requested file is currently being transferred.

 

 

Waiting

 

 

The request is waiting in the background transfer service queue. This status can indicate that the request is queued and waiting for previous transfers to be completed or that the service is retrying the request due to a network error.

 

 

WaitingForWiFi

 

 

The request is waiting in the background transfer service queue for a Wi-Fi connection.

 

 

WaitingForExternalPower

 

 

The request is waiting in the background transfer service queue for external power to be connected.

 

 

WaitingForExternalPower-DueToBatterySaverMode

 

 

The request is waiting for the device to be connected to external power because the user has enabled battery saver mode on the device.

 

 

WaitingForNonVoiceBlockingNetwork

 

 

The background transfer service does not run when the device is on a non-simultaneous voice and data network, including 2G, EDGE, and standard GPRS. This status indicates that the service is waiting for a supported network connection.

 

 

Paused

 

 

The request has been paused and is waiting in the background transfer service queue.

 

 

Completed

 

 

The request has been completed. This means that the request is no longer actionable by the background transfer service regardless of whether the transfer was completed successfully. To confirm that a transfer was successful, confirm that the TransferError property is null.

 

 

Unknown

 

 

The background transfer service could not retrieve the request status from the service. Once in this state, a BackgroundTransferRequest object is no longer usable. You can attempt to retrieve a new instance by using the Find(String) method.

 

 

 

BTS value

 

 

BT value

 

 

None / Waiting

 

 

Idle

 

 

Transferring

 

 

Running

 

 

WaitingForWiFi

 

 

PausedCostedNetwork

 

 

WaitingForExternalPowerDueToBatterySaverMode

 

 

PausedSystemPolicy

 

 

WaitingForNonVoiceBlockingNetwork

 

 

PausedSystemPolicy

 

 

Paused

 

 

PausedByApplication

 

 

Completed

 

 

Completed

 

 

Cancellation offers perhaps the clearest illustration of the architectural differences between BTS and BT that I described earlier. The BackgroundTransferService object in BTS acts as a proxy to the OS-provided service of the same name, and that service runs independently of any individual transfer or app. As a result, it makes sense that it allows apps to cancel transfers by calling a method (Remove) with a reference to the transfer. By contrast, because BT is based on the BackgroundTask infrastructure, you cancel a transfer simply by canceling the task.

Here is the simple example of the cancellation code in each API.

 

BTS

 

 

//Use Find to retrieve the transfer request with the

//specified ID.

BackgroundTransferRequest transferToRemove = BackgroundTransferService.Find(transferID);

//Cancel this operation by trying to remove the transfer

//from the background transfer service.

try

{

BackgroundTransferService.Remove(transferToRemove);

}

 

BT

 

 

//Find the transfer to be canceled.

DownloadOperation operationtocancel;

 

foreach (var transfer in transferRequests)

{

if(transfer.Guid == transferGuid)

{

operationtocancel = transfer;

}

}

 

//Attach the progress handler back.

cts = new CancellationTokenSource();

await operationtocancel.AttachAsync().

AsTask(cts.Token, progressCallback);

//Cancel the task.

cts.Cancel();

cts.Dispose();

 

 

 

 

 

 

 

Conclusion

 

 

Updating your Windows Phone app to use the Windows Runtime BackgroundTransfer (BT) API provides some real advantages, including code reuse across Windows platforms, an improved feature set, and better overall performance for background file transfers. Now you have all the info you need to migrate your app from BTS to BT and deliver a better experience to your users, and I hope you’ll also look further into all that’s becoming possible with universal apps that target both Windows and Windows Phone platforms. bd2d9a5d8ecbabd6f48c82238fc16894._.gif.0f7422d525c85c306914e3dd97e03eb8.gif

 

Continue reading...

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...