Checking the Internet Connection
All Windows Phone devices have a built-in network connection but, for the same reason we learned how to locally store data, we need to be ready to manage how users are using our application while a connection is missing.
For this purpose, the Windows Phone framework includes a class that can be used to discover information about the Internet connection called DeviceNetworkInformation
, which is part of the Microsoft.Phone.Net.NetworkInformation
namespace.
The most important one is IsNetworkAvailable
, which tells us whether an Internet connection is available. We should always use this API before performing an operation that requires a connection, like the following sample:
private void OnCheckConnectionClicked(object sender, RoutedEventArgs e) { if (DeviceNetworkInformation.IsNetworkAvailable) { MessageBox.Show("You are connected to Internet"); //Perform network operations. } else { MessageBox.Show("You aren't connected to Internet"); } }
The class also offers an event called NetworkAvailabilityChanged
which is triggered every time the connection status changes. It’s useful if you want to quickly react to network changes, such as enabling or disabling certain application features.
public MainPage() { InitializeComponent(); DeviceNetworkInformation.NetworkAvailabilityChanged += DeviceNetworkInformation_NetworkAvailabilityChanged; } private void DeviceNetworkInformation_NetworkAvailabilityChanged(object sender, NetworkNotificationEventArgs e) { if (e.NotificationType == NetworkNotificationType.InterfaceDisconnected) { MessageBox.Show("Disconnected"); } else if (e.NotificationType == NetworkNotificationType.InterfaceConnected) { MessageBox.Show("Connected"); } }
The return parameters contain a property called NotificationType
, of the type NetworkNotificationType
, which tells us the current network status.
However, with the DeviceNetworkInformation
you’ll be able to also get other information about the current network status, like whether the user has enabled the cellular data connection (IsCellularDataEnabled
), the Wi-Fi connection (IsWiFiEnabled
), or roaming options (IsCellularDataRoamingOptions
).
The framework offers another useful class to deal with network connections called NetworkInterface
. By using the NetworkInterfaceType
property, you’ll be able to identify which connection type is currently in use. For example, we can use this property to avoid downloading big files while using a cellular connection.
NetworkInterfaceType
is an enumerator that can assume many values. The most important ones are:
-
MobileBroadbandGsm
andMobileBroadbandCdma
when the phone is connected to a cellular network (GSM or CDMA, according to the country) -
Wireless80211
, when the phone is connected to a Wi-Fi network
In the following sample, we display a message on the screen with the current connection type:
private void OnCheckConnectionTypeClicked(object sender, RoutedEventArgs e) { if (NetworkInterface.NetworkInterfaceType == NetworkInterfaceType.MobileBroadbandGsm || NetworkInterface.NetworkInterfaceType == NetworkInterfaceType.MobileBroadbandCdma) { MessageBox.Show("Mobile"); } else if (NetworkInterface.NetworkInterfaceType == NetworkInterfaceType.Wireless80211) { MessageBox.Show("Wi-Fi"); } }
Performing Network Operations: HttpClient
The Windows Phone framework has two built-in classes for performing network operations: WebClient
and HttpWebRequest
. Unfortunately, neither of them is perfect. WebClient
is very easy to use, but it’s based on the old callback approach (unless you install the Async for .NET package we discussed earlier in this series). HttpWebRequest
is very powerful, but it is complex to use and based on an old asynchronous pattern that is hard to understand.
The Windows Runtime has introduced a new class called HttpClient
, which takes the best of both worlds. It’s powerful and offers great performance, but it’s easy to use and offers methods that are based on the new async and await pattern. This class is available in the full Windows Runtime for Windows Store apps, but it’s not included in the Windows Phone Runtime subset—you’ll have to install it from NuGet.
The HttpClient
class, as we’ll see later, is great not just for performing generic network operations like downloading and uploading file, but also for interacting with web services. In fact, it exposes asynchronous methods for every HTTP command, like GET, POST, PUT, etc.
Note: To be able to interact with the network you’ll have to enable the ID_CAP_NETWORKING option in the manifest file. It is enabled in every new Windows Phone project by default.
Downloading Data
Files are usually downloaded using the GET HTTP command, so HttpClient
offers the GetAsync()
method. To make developers’ lives simpler, HttpClient
has some built-in methods to download the most common file types, such as GetStringAsync()
for downloading text files like XML, RSS, or REST responses; or GetByteArrayAsync()
and GetStreamAsync()
to get binary file content.
Downloading strings is really easy. The method GetStringAsync()
requires as a parameter the file’s URL and returns the file’s content as a string. In the following sample, you can see how to download my blog’s RSS feed:
private async void OnDownloadStringClicked(object sender, RoutedEventArgs e) { HttpClient client = new HttpClient(); string result = await client.GetStringAsync("http://feeds.feedburner.com/qmatteoq_eng"); }
Once you have the string, you can perform the required operations according to your scenario. For example, in the previous sample I could have parsed the returned XML with LINQ to XML to display the news list on the screen.
Downloading binary files can be accomplished in many ways. You can use GetByteArrayAsync()
if you prefer to work with bytes, or GetStreamAsync()
if you prefer to manipulate the file’s content as a stream.
In the following sample, you’ll see how to download a picture using the GetByteArrayAsync()
method. It returns a byte’s array, which can be easily saved in the local storage using the APIs we learned about earlier in this series.
private async void OnDownloadFileClicked(object sender, RoutedEventArgs e) { HttpClient client = new HttpClient(); byte[] bytes = await client.GetByteArrayAsync("http://www.syncfusion.com/Content/en-US/Home/Images/syncfusion-logo.png"); StorageFile storageFile = await ApplicationData.Current.LocalFolder.CreateFileAsync("picture.png", CreationCollisionOption.ReplaceExisting); IRandomAccessStream accessStream = await storageFile.OpenAsync(FileAccessMode.ReadWrite); using (IOutputStream outputStream = accessStream.GetOutputStreamAt(0)) { DataWriter writer = new DataWriter(outputStream); writer.WriteBytes(bytes); await writer.StoreAsync(); } }
By using the DataWriter
class, we’re able to save the byte array returned by the HttpClient
class into a file in the local storage called picture.png.
If you need full control over the download operation, you can use the generic GetAsync()
method, which returns a HttpResponseMessage
object with the entire response’s content, like headers, status code, etc.
In the following sample you can see how, by using the GetAsync()
method, we’re able to download a picture as a Stream
and display it in an Image
control placed on the page. To the method we pass a second parameter of type HttpCompletionOption
, which tells the class when to mark the operation as completed. Since we want the full content of the response (which is the downloaded image), we use the ResponseContentRead
option.
private async void OnDownloadStreamClicked(object sender, RoutedEventArgs e) { HttpClient client = new HttpClient(); HttpResponseMessage httpResponseMessage = await client.GetAsync("http://www.syncfusion.com/Content/en-US/Home/Images/syncfusion-logo.png", HttpCompletionOption.ResponseContentRead); Stream stream = await httpResponseMessage.Content.ReadAsStreamAsync(); BitmapImage image = new BitmapImage(); image.SetSource(stream); Logo.Source = image; }
Notice that the specific methods we’ve seen offered by the HttpClient
class are simply a shortcut to the methods offered by the Content
property of the HttpResponseMessage
class (in the previous sample, we use the ReadAsStreamAsync()
method to return the response’s content as a Stream
).
Uploading Data
Uploading data is accomplished in a similar way: the operation is usually performed using the POST command, so the HttpClient
class exposes the PostAsync()
method for this purpose.
The content to send is prepared using the HttpContent
class, which offers many implementations: StreamContent
to send a file’s stream, ByteArrayContent
to send a binary file, StringContent
to send a string, or MultipartFormDataContent
to send content encoded using multipart/form-data MIME type.
In the following sample, you can see how to upload a file’s stream to a service:
private async void OnUploadFileClicked(object sender, RoutedEventArgs e) { StorageFile storageFile = await ApplicationData.Current.LocalFolder.GetFileAsync("picture.png"); IRandomAccessStream accessStream = await storageFile.OpenAsync(FileAccessMode.ReadWrite); HttpClient client = new HttpClient(); HttpContent content = new StreamContent(accessStream.AsStreamForRead()); await client.PostAsync("http://wp8test.azurewebsites.net/api/values", content); }
After we have retrieved the stream of a file stored in the local storage, we pass it to a new instance of the StreamContent
class. Then, we call the PostAsync()
method, passing the service’s URL and the HttpContent
object as parameters.
Using REST Services
REST (Representational State Transfer) is, without a doubt, the most used approach nowadays in web service development, especially in the mobile world.
REST services have become very popular for two reasons:
- They are based on the HTTP protocol and they expose operations using the standard HTTP commands (like GET, POST, PUT, etc.).
- They return data using standard languages like XML and JSON.
Almost every platform natively supports these technologies, so you don’t have to look for special libraries to interact with them as is needed for WSDL-based web services.
We’ve already seen how, with the HttpClient
class, it’s simple to interact with the web by using the standard HTTP commands. Most of the time, to interact with a REST service, you’ll simply have to execute the GetStringAsync()
method to get the XML or JSON response.
Once you have the result, most of the time you’ll have to convert it into objects to be used inside the application. Earlier in this series, we discussed the easiest way to accomplish this task: deserialization, which means translating plain text into complex objects. We can use the DataContractSerializer
or DataContractJsonSerializer
classes to do this. In this case, you just have to refer to the deserialization process since the procedure is the same.
private async void OnConsumeServiceClicked(object sender, RoutedEventArgs e) { HttpClient client = new HttpClient(); string result = await client.GetStringAsync("http://wp8test.azurewebsites.net/api/values"); using (MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(result))) { DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(List<Person>)); List<Person> people = serializer.ReadObject(ms) as List<Person>; } }
We assume that the service returns, in JSON format, a list of persons:
[ { "id":1, "name":"Matteo", "surname":"Pagani" }, { "id":2, "name":"John", "surname":"Doe" } ]
With the help of the DataContractJsonSerializer
class, we are able to convert the previous JSON into a list of Person
objects, which is the same class we have used in many other samples in this series. The difference in this sample is that we are able to control the serialization process, in case, for example, the property names returned from the JSON are different than the ones we use in our classes. This is a very common scenario when dealing with JSON since property names are typically lowercase, while in C# objects they are CamelCase. This result is achieved by using the [DataMember]
attribute, which can be applied to the properties we want to serialize. In the following sample, you can see that the attribute offers a property called Name
, which can be used to specify which property name we expect to find in the JSON file.
public class Person { [DataMember(Name = "id")] public int Id { get; set; } [DataMember(Name = "name")] public string Name { get; set; } [DataMember(Name = "surname")] public string Surname { get; set; } }
This approach has a downside: REST services always return a plain string, while the DataContractJsonSerializer
class requires a Stream
as an input parameter of the ReadObject()
method, so we’re always forced to convert it using a MemoryStream
object.
There is another way to accomplish the same result. Let me introduce JSON.NET, a third-party library that offers some additional useful features for handling JSON data. In addition, it offers better performance and is able to deserialize complex JSON files quicker.
It can be easily installed using NuGet, and its official website offers comparisons with other JSON libraries and detailed documentation.
In the following sample, we use JSON.NET to achieve the same result as the code that we’ve previously used:
private async void OnGetDataClicked(object sender, RoutedEventArgs e) { HttpClient client = new HttpClient(); string result = await client.GetStringAsync("http://wp8test.azurewebsites.net/api/values"); List<Person> people = JsonConvert.DeserializeObject<List<Person>>(result); }
The JsonConvert
class (which is part of the Newtonsoft.Json
namespace) exposes the DeserializeObject<T>()
method, where T
is the object’s type we expect in return. As an input parameter, it requires only the JSON string that we’ve downloaded from the service.
It’s also possible to control the deserialization process using attributes, like we previously did with the DataMember
attribute. In the following sample, you can see how we can manually define how JSON properties should be translated:
public class Person { [JsonProperty("id")] public int Id { get; set; } [JsonProperty("name")] public string Name { get; set; } [JsonProperty("surname")] public string Surname { get; set; } }
Tip: You will often have to use third-party services, so you won’t know the exact mapping between entities and JSON data. There is a website that will help you in this scenario: http://json2csharp.com/. Simply paste the JSON returned by your service, and it will generate for you the needed C# classes to map the JSON data.
LINQ to JSON
Another interesting feature introduced by JSON.NET is LINQ to JSON, which is a LINQ-based language that, similar to LINQ to XML, can be used to manipulate a JSON string to extract just the information you need. This approach is useful when you do not really need to use deserialization, but just need to extract some data from the JSON response you received from the service.
The starting point to use LINQ to JSON is the JObject
class, which identifies a JSON file. To start working with it, you simply have to call the Parse()
method, passing as parameter the JSON string, as shown in the following sample:
private async void OnParseJson(object sender, RoutedEventArgs e) { HttpClient client = new HttpClient(); string result = await client.GetStringAsync("http://wp8test.azurewebsites.net/api/values"); JObject json = JObject.Parse(result); }
Now you’re ready to execute some operations. Let’s take a look at the most common ones.
Simple JSON
Here is an example of a simple JSON file:
{ "Id":1, "Name":"Matteo", "Surname":"Pagani" }
With LINQ to JSON, we are able to extract a single property’s value in the following way:
private async void OnParseJson(object sender, RoutedEventArgs e) { HttpClient client = new HttpClient(); string result = await client.GetStringAsync("http://wp8test.azurewebsites.net/api/values/1"); JObject json = JObject.Parse(result); string value = json["Name"].Value<string>(); }
The JObject
class is treated like a collection, so you can simply access a property using its name as a key. In the end, you can extract the value by using the Value<T>()
method, where T
is the data type we expect to be stored.
Complex JSON
Like C# objects, JSON objects can also have complex properties, as shown in the following sample:
{ "Id":1, "Name":"Matteo", "Surname":"Pagani", "Address": { "Street":"Fake address", "City":"Milan" } }
Address
is a complex property because it contains other nested properties. To access these properties, we need to use the SelectToken()
method, passing the full JSON path as a parameter:
private async void OnParseJson(object sender, RoutedEventArgs e) { HttpClient client = new HttpClient(); string result = await client.GetStringAsync("http://wp8test.azurewebsites.net/api/values/1"); JObject json = JObject.Parse(result); string city = json.SelectToken("Address.City").Value<string>(); }
With the Address.City
path, we are able to extract the value of the City
property that is part of the Address
node.
JSON Collections
When you handle JSON collections, you can use the Children()
method to get access to all the children nodes of a specific property. Let’s use, as an example, a JSON code that we’ve previously seen:
[ { "Id":1, "Name":"Matteo", "Surname":"Pagani" }, { "Id":2, "Name":"John", "Surname":"Doe" } ]
In this case, we can use the JArray
class and the Children()
method to extract all the collection’s elements. In the following sample you can see how we use it to get a subcollection with only the Name
property’s values.
private async void OnGetDataClicked(object sender, RoutedEventArgs e) { HttpClient client = new HttpClient(); string result = await client.GetStringAsync("http://wp8test.azurewebsites.net/api/values"); JArray json = JArray.Parse(result); List<string> list = json.Children().Select(x => x["Name"].Value<string>()).ToList(); }
Background Transfers
The HttpClient
class we’ve previously seen, like the WebClient
and HttpWebRequest
classes, can be used only for foreground operations. When the application is suspended, network transfers are canceled.
When we have to deal with big data transfers, forcing the user to keep the app opened doesn’t create the best user experience. For this scenario, Windows Phone 7.5 has introduced background transfer APIs that can be used to start a download or upload operation and to continue it even if the app is suspended.
However, there are some limitations that have been introduced to avoid battery issues and high data plan consumption:
- If the phone is connected to a cellular network, files bigger than 20 MB cannot be downloaded.
- If the phone is connected to a Wi-Fi network, files bigger than 100 MB can’t be downloaded.
- The 100 MB limit can be exceeded only if the phone is connected to a Wi-Fi network and the battery is charging.
- A single application can queue up to 25 background transfer operations.
- The global operating system’s queue can contain up to 500 background transfer operations.
- The phone can execute a maximum of two transfer operations at a time.
A background transfer is identified by the BackgroundTransferRequest
class, which is part of the Microsoft.Phone.BackgroundTransfer
namespace. As developers, we have control over some conditions that need to be satisfied for a background transfer created in our application to start, thanks to the TransferPreferences
property that can get the following values:
-
None
, the default value: The transfer is started only if the phone is connected to a Wi-Fi network and the battery is charging. -
AllowBattery
: The transfer is started only if the phone is connected to a Wi‑Fi network, regardless of the power source. -
AllowCelullar
: The transfer is started only if the phone is charging, regardless of the network connection.
AllowCellularAndBattery
: Always starts the transfer, regardless of the connection and power source conditions.
The BackgroundTransferRequest
class exposes two event handlers that can be used to control the transfer:
-
TransferStatusChanged
is triggered when the transfer’s status changes. The parameter returned by the method contains aTransferStatus
object that notifies you of the current status (likeCompleted
when the transfer ends, orPaused
when the transfer is paused). There are also specific statuses that start with theWaiting
prefix that tell you when a transfer is suspended because the conditions defined in theTransferPreferences
property are not satisfied. For example,WaitingForWiFi
is set when the transfer is waiting for the phone to be connected to a Wi-Fi network to start. -
TransferProgressChanged
is triggered when a transfer’s progress changes, meaning that new data has been downloaded or uploaded. Usually, this event handler is connected to aProgressBar
control since it exposes properties to notify you how much data has been transferred and how much data still needs to be downloaded or sent.
After you’ve defined a background transfer, you need to add it to the operating system’s queue. Windows Phone will take care of starting it when the specified conditions are satisfied. To accomplish this task, we use the BackgroundTransferService
class, which is the central background transfer manager. You can add, remove, or list background transfers that belong to the application.
In the following sample you can see a background transfer definition:
private BackgroundTransferRequest backgroundRequest; private void OnStartBackgroundDownloadClicked(object sender, RoutedEventArgs e) { Uri sourceUrl = new Uri("http://wpsauce.com/wp-content/uploads/2011/11/windows_phone_logo.jpg"); Uri destinationUrl = new Uri("/Shared/Transfers/windows_phone_logo.jpg", UriKind.RelativeOrAbsolute); backgroundRequest = new BackgroundTransferRequest(sourceUrl, destinationUrl); backgroundRequest.TransferStatusChanged += backgroundRequest_TransferStatusChanged; backgroundRequest.TransferPreferences = TransferPreferences.AllowCellularAndBattery; BackgroundTransferService.Add(backgroundRequest); } void backgroundRequest_TransferStatusChanged(object sender, BackgroundTransferEventArgs e) { if (backgroundRequest.TransferStatus == TransferStatus.Completed) { //Manage the downloaded file. BackgroundTransferService.Remove(backgroundRequest); } }
We register this transfer to be executed regardless of the available network connection and power source. The previous sample is related to a download operation, so we need to define a source URI (the file to download) and a destination URI (the local storage path where the file will be saved). Unlike what we’ve seen with HttpClient
, we don’t have to take care of the saving process; the file will be automatically downloaded and saved in the local storage since the download can also finish when the app is suspended. Both source and destination URIs are passed as parameters of the BackgroundTransferRequest
constructor.
Note: Background transfers that are used to perform download operations always have to save the file inside the Shared/Transfers path in the local storage, which is automatically created when the app is installed—otherwise you’ll get an exception. When the download is complete, you are free to move the file to another position if needed, but you can’t schedule a background transfer that tries to download a file in a different folder.
Next, we subscribe to the TransferStatusChanged
event. If the download is completed while the app is in the foreground, we are able to manage the downloaded file—for example, if it’s an image, we can display it. Notice the Remove()
operation that we perform on the BackgroundTransferService
class. It’s really important to always perform this task because the operating system won’t automatically remove completed transfers from the application’s queue and it can lead to unexpected issues since an application can’t schedule more than 25 transfers.
Instead, if you need to upload a file, you’ll need to create a BackgroundTransferRequest
object in a different way. You still need to define two URIs: the source (the file to upload) and the destination (a service that is able to receive the file using the HTTP command set in the Method
property). The destination URI can be passed in the BackgroundTransferRequest
’s constructor (like we did previously), but the source URI needs to be set in the UploadLocation
property, like in the following sample:
private void OnUploadFile() { Uri destinationUrl = new Uri("http://wp8test.azurewebsites.com/api/values", UriKind.Relative); Uri sourceUri = new Uri("/Shared/Transfers/image.png", UriKind.Relative); BackgroundTransferRequest request = new BackgroundTransferRequest(destinationUrl); request.UploadLocation = sourceUri; request.Method = "POST"; BackgroundTransferService.Add(request); }
Conclusion
In this article we’ve seen how to work with one of the most used features of a smartphone: an Internet connection. In detail, we’ve learned:
- Even if an Internet connection is a must-have for every device, we should be aware that sometimes users may not have an available connection. It’s important to properly check whether the phone is connected to the Internet before doing any network operation.
-
HttpClient
is a new class introduced in Windows Runtime that helps perform network operations. We’ve seen how to use it to download and upload files, and interact with services. - Downloading and uploading files is a common task, but nowadays more and more applications have to interact with web services to get the data they need. In this article we’ve learned how, thanks to the JSON.NET library, it’s easy to work with REST services and convert JSON data into C# objects.
-
HttpClient
is a great help, but it works only if the application is in the foreground. When it’s suspended, network operations are canceled. For this purpose, the framework offers some specific APIs to perform download and upload operations even in the background when the app is not in use.
This tutorial represents a chapter from Windows Phone 8 Succinctly, a free eBook from the team at Syncfusion.
Comments