Transfer requests are represented by the BackgroundTransferRequest
class. The BackgroundTransferService
maintains a queue of background requests and is used to submit new
background requests, remove requests from the queue, and retrieve
active requests.
Submitting a background request can be done by creating an instance of the BackgroundTransferRequest
class, specifying the request end points, and then adding the request to the BackgroundTransferService
. The following excerpt shows a transfer request that downloads a file from a remote server to a location in isolated storage:
BackgroundTransferRequest request
= new BackgroundTransferRequest(remoteUri, localUri)
{
TransferPreferences = TransferPreferences.AllowBattery,
Method = "Get",
};
BackgroundTransferService.Add(request);
Note
An app can have at most five requests queued at a given time. Attempting to add more than five raises an InvalidOperationException
. It is the responsibility of the app to remove requests from the queue by using the BackgroundTransferService.Remove
method after requests have completed.
By default, background transfer requests
occur only when the device has a Wi-Fi connection and is connected to
external power. By using the TransferPreferences
property of the BackgroundTransferRequest
class, you can override this behavior so that transfers occur when one or both of these conditions are not met. Table 1 describes the available TransferPreferences
values.
TABLE 1. TransferPreferences
Enum
Note
Setting the TransferPreferences
property does not guarantee that transfers will occur under the
preferred conditions. If the battery level is critical, for example,
background transfers are suspended regardless of the TransferPreferences
value.
Caution
Transferring files when the phone does not
have a Wi-Fi connection can unduly consume the user’s data plan. In
addition, transferring files without an external power connection can
rapidly drain the phone’s battery. Both cases can potentially result in
a poor experience for the user; therefore, it is recommended to leave
the default value of TransferPresences
as None.
BackgroundTransferRequest
is bidirectional, allowing you to transfer files from and to the phone device. The BackgroundTransferRequest
API is peculiar in that it determines the direction of the request
based on which of its two constructors is used, and whether its UploadLocation
property has been set. The constructor to use when performing a
download (from a remote server to isolated storage) has two parameters:
the remote URI and the local (destination) URI. To perform an upload
(from isolated storage to a remote server), its single parameter
constructor is used in conjunction with its UploadLocation
property. The following excerpt demonstrates the creation of an upload transfer request:
Uri remoteUri = new Uri(remoteUrl, UriKind.Absolute);
BackgroundTransferRequest request
= new BackgroundTransferRequest(remoteUri)
{
Method = "POST",
UploadLocation = new Uri(uploadPath, UriKind.Relative)
};
BackgroundTransferService.Add(request);
By default, BackgroundTransferRequest
uses the HTTP method GET.
Note
If you are performing an upload and fail to set the method to POST, an ArgumentNullException
is raised because the BackgroundTransferRequest
mistakes your request for a download and complains that the download URI was not supplied. Conversely, if Method
is set to anything other than GET, BackgroundTransferRequest
assumes the transfer is an upload and raises an ArgumentNullException
if UploadLocation
is not specified.
It is another peculiar aspect of the API that an ArgumentNullException
is raised rather than an InvalidOperationException
.
A parameter indicating the direction and nature of the transfer would, in my view, make the BackgroundTransferRequest
easier to use.
BackgroundTransferRequest
provides the following two events for monitoring the progress and status of a background transfer:
- TransferProgressChanged
- TransferStatusChanged
Both events pass a BackgroundTransferEventArgs
object that provides nothing apart from a reference to the associated BackgroundTransferRequest
.
The TransferProgressChanged
event, as its name implies, allows you to track the amount of data that has been transferred. The following excerpt shows a TransferProgressChanged
event handler that determines the current progress of a transfer as a value between 0 and 1:
void HandleTransferProgressChanged(object sender,
BackgroundTransferEventArgs e)
{
if (e.Request.BytesSent > 0)
{
Progress = (double)e.Request.TotalBytesToSend / e.Request.BytesSent;
}
else
{
Progress = 0;
}
}
The TransferStatusChanged
event allows you to monitor the critical events of the transfer request
and enables you to determine, for example, when the transfer has
completed and whether an error has occurred, as shown:
void HandleTransferStatusChanged(object sender,
BackgroundTransferEventArgs e)
{
if (e.Request.TransferStatus == TransferStatus.Completed)
{
BackgroundTransferService.Remove(e.Request);
if (e.Request.TransferError != null)
{
/* Handle the error. */
return;
}
}
}
The Request.TransferStatus
property identifies the request’s current state. Table 2 describes each TransferStatus
enum value.
TABLE 2. TransferStatus
Enumeration
Handling App Termination and Resubscription to Transfer Events
When a BackgroundTransferRequest
has been added to the BackgroundTransferService
, you can store the value of the request’s RequestId
property in isolated storage. This enables you to retrieve the request
later if your app is terminated, and to continue monitoring the
progress of your background request by resubscribing to the request’s TransferStatusChanged
and TransferProgressChanged
events.
The BackgroundTransferService.Find
method is used to retrieve an existing request, like so:
BackgroundTransferRequest request
= BackgroundTransferService.Find("request id string");
if (request != null)
{
request.TransferStatusChanged += HandleUploadTransferStatusChanged;
request.TransferProgressChanged += HandleTransferProgressChanged;
}