Internet data access (Android versus Windows Store apps)
[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]
In this article, you'll learn how to work with data from the Internet in your Windows Store apps.
It's more than likely that your Windows Store apps will need to work with data that is accessed through the Internet. For example, an app may aggregate data from various news sources using Really Simple Syndication (RSS) feeds. Working with this type of data in a Windows Store app is similar to an Android app. In this article, you'll learn how to write code that lets Windows Store apps connect to the network, manage network usage, and parse XML data.
Connect to the network
For a Windows Store app to access the Internet, it must have the internetClient
capability enabled in its project's manifest. By default, when you create a new Windows Store app using Microsoft Visual Studio, this capability is enabled for you. To confirm this in Visual Studio:
- In the Solution Explorer window, double-click the
Package.appxmanifest
file to open it. - On the Capabilities tab, the box next to Internet (Client) is checked.
Android tip |
---|
To connect to a network in Android, you declare this permission in the Android app's manifest:
|
Top
Mange network usage
It's important to consider how your Windows Store app will access network resources. If your app is going to perform a large number of network operations or transfer large amounts of data (like audio and video streaming), your users should control when these operations are performed. Windows enables users to specify whether a connection is metered. (A metered connection is one where an Internet service provider (ISP) charges by the amount of data that is sent and received.) A user can specify in Windows whether a connection is metered as follows:
- Tap or click the Settings charm.
- Tap or click the network icon.
- Press and hold, or right-click, the desired network, and then tap or click Set as metered connection or Set as non-metered connection.
An example of a metered connection is a Wi-Fi hotspot. For an audio and video streaming app, you should give the user the option to stream media only when the device is connected to a non-metered network.
Here's how to do this for your Windows Store app:
Create an enumeration representing various states of connectivity.
public enum ConnectionState { NonMetered, Metered, NotConnected, Unknown }
Create a method that uses the ConnectionProfile and ConnectionCost classes to determine if the device the app is running on is connected to a network and, if the device is connected, what kind of network the device is on.
private ConnectionState GetConnectionState() { bool connected = false; var profile = NetworkInformation.GetInternetConnectionProfile(); // Is the device connected to a network? try { var connectivityLevel = profile.GetNetworkConnectivityLevel(); if (connectivityLevel == NetworkConnectivityLevel.InternetAccess) connected = true; } catch { } if (connected) { // The device is connected to a network. Determine if // the network is metered. var cost = profile.GetConnectionCost(); if (cost.NetworkCostType == NetworkCostType.Unrestricted) return ConnectionState.NonMetered; else if (cost.NetworkCostType == NetworkCostType.Fixed || cost.NetworkCostType == NetworkCostType.Variable) return ConnectionState.Metered; else return ConnectionState.Unknown; } else { return ConnectionState.NotConnected; } }
Add a method to your class that will perform an operation based on the connection state.
private void UpdateActivityBasedOnState() { GetConnectionState(); // Perform some action based on state // (for example start or stop streaming media). }
In your class's constructor, add an event handler that runs when the network status changes for a connection. This will enable your app to determine if a connection has been lost or if the device has switched to a metered or non-metered connection.
public NetworkManager() { UpdateActivityBasedOnState(); NetworkInformation.NetworkStatusChanged += NetworkInformation_NetworkStatusChanged; } private void NetworkInformation_NetworkStatusChanged(object sender) { UpdateActivityBasedOnState(); }
Android tip |
---|
For Android apps, to get info about the networks that a device is connected to, declare the following manifest permission:
Then use the ConnectivityManager and NetworkInfo classes to determine what type of network the device is connected to. The following code shows how to determine whether a device is connected to a Wi-Fi or mobile network.
|
Top
Parse XML data
Now that your app can connect to a network and manage its network usage, your app can start actually working with data. Two of the most common data formats in use on the Internet today are XML and JavaScript Object Notation (JSON). Web sites that update their content frequently, like blogs, often provide an XML feed so that apps can keep up with the site's content changes. This section shows you how to parse an XML document and use its data in your apps.
Of course, first you'll need to figure out which XML feed you want to use. For the following example, we'll use a feed from Stack Overflow that focuses on questions tagged about Windows 8. This feed was last accessed at http://stackoverflow.com/feeds/tag/windows-8 at the time that this article was written.
After you've located the desired feed, you'll want to figure out which parts of the feed are of interest to your app. Following is a sample abstract of the feed for this example, using the XML schema that was current when this article was written, and with ellipses (...) representing irrelevant portions of the feed that are omitted for brevity:
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"
xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule"
xmlns:re="http://purl.org/atompub/rank/1.0">
<title type="text">active questions tagged windows-8 - Stack Overflow</title>
...
<entry>
...
</entry>
<entry>
<id>http://stackoverflow.com/q/00000000</id>
<re:rank scheme="http://stackoverflow.com">0</re:rank>
<title type="text">Windows Store XML Data</title>
<category scheme="http://stackoverflow.com/feeds/tag/windows-8/tags" term="c#"/>
<category scheme="http://stackoverflow.com/feeds/tag/windows-8/tags" term="xml"/>
<category scheme="http://stackoverflow.com/feeds/tag/windows-8/tags" term="windows-8"/>
<category scheme="http://stackoverflow.com/feeds/tag/windows-8/tags" term="windows-runtime"/>
<author>
<name>anonymous</name>
<uri>http://stackoverflow.com/users/000000</uri>
</author>
<link rel="alternate" href="http://stackoverflow.com/questions/00000000/windows-store-xml-data" />
<published>1900-01-01T00:00:00Z</published>
<updated>1900-01-01T00:00:00Z</updated>
<summary type="html">
<p>How do I use XML in Windows Store apps?</p>
</summary>
</entry>
<entry>
...
</entry>
</feed>
For this example, we'll focus only on the <entry>
element's <title>
, <link>
, and <summary>
child elements. First, create a class that represents the data that your app needs to work with. Since this example focuses on the <title>
, <link>
, and <summary>
elements of the feed, the class will look like this.
public class FeedEntry
{
public string Title { get; set; }
public string Link { get; set; }
public string Summary { get; set; }
}
Next, create a class and a method to parse the data, with the method's return type to be a list of FeedEntry
objects. Here's an example.
public class StackOverflowXmlParser
{
// ...
public async Task<List<FeedEntry>> Parse()
{
// ...
}
// ...
}
Notice that the async keyword modifier is added to the method, and the method returns a Task, which has been typed as a List of FeedEntry
objects. This enables the method to use the await operator (shown later) to tell the system that the async method can't continue past the await call until the asynchronous operation is complete. Additionally, this makes it easy for calling methods to call the Parse
method asynchronously by simply using the await operator.
Android tip |
---|
Using the async keyword and await operator in Windows Store apps to simplify asynchronous programming is similar to using the AsyncTask class in Android apps. |
The first job of the Parse
method is to create a result set to return to the calling method, and check the status of network connectivity using the GetConnectionState
previously described. Because there could be a large amount of XML returned, the feed should only be accessed if the device is on a non-metered connection.
// ...
List<FeedEntry> results = new List<FeedEntry>();
// Determine connection state.
var connectionState = GetConnectionState();
// Proceed if a non-metered connection is detected.
if (connectionState == ConnectionState.NonMetered)
{
// ...
}
// ...
Next, determine how to process the XML feed results. You have 3 namespace options with Windows Store apps: System.Xml, System.Xml.Linq, and System.ServiceModel.Syndication.
The System.Xml namespace provides standards-based support for processing XML. It gives you a good measure of control over how you process XML and allows you to use things like XSD schemas, XPath expressions, and Extensible Stylesheet Language Transformations (XSLT) transformations. It's more power than we need for this particular example. The SyndicationFeed class in the System.ServiceModel.Syndication namespace would actually make our job quite simple if we wanted to work with all of the elements in the feed. However, since we're only concerned with three elements, we'll use the System.Xml.Linq namespace. This namespace contains the classes for Language Integrated Query (LINQ) to XML, which serves as an in-memory XML programming interface that enables more efficient processing of XML data.
To work with LINQ to XML, create XName objects that represent the names of the elements that we want to work with. These names need to include both the local and namespace names:
// ...
// Declare the Atom namespace.
var atomNamespace = "http://www.w3.org/2005/Atom";
// Create the names of the XML elements including the Atom namespace.
var entryXName = XName.Get("entry", atomNamespace);
var titleXName = XName.Get("title", atomNamespace);
var linkXName = XName.Get("link", atomNamespace);
var summaryXName = XName.Get("summary", atomNamespace);
// ...
Next, load the XML data into an XElement object asynchronously. To do this, create an HttpWebRequest object and call its GetResponseAsync method, using the await operator. The HttpWebResponse object's GetResponseStream method can then be used in the XElement object's Load method:
// ...
var request = HttpWebRequest.CreateHttp("http://stackoverflow.com/feeds/tag/windows-8");
// Load the XML data asynchronously.
var response = await request.GetResponseAsync();
XElement root = XElement.Load(response.GetResponseStream());
// ...
Android tip |
---|
The preceding approach is similar to using HttpURLConnection and InputStream in Android apps:
You would then use the InputStream output as input into the XmlPullParser class's setInput method. |
After the XElement object is loaded, use LINQ to query for just the <entry>
elements and store them in a list.
// ...
// Load all <entry> elements from the XML into a list.
var entries = (from e in root.Elements(entryXName) select e).ToList();
// ...
Next, start iterating through the list of entries by creating a new FeedEntry
object.
// ...
// Iterate all <entry> elements.
foreach (var entry in entries)
{
// Create a new FeedEntry.
var feedEntry = new FeedEntry();
// ...
}
// ...
Then assign the value of the FeedEntry
object's Title
property to the value of the <title>
element.
// ...
// Get the <title>.
var titleElement = (from e in entry.Elements(titleXName) select e).FirstOrDefault();
if (titleElement != null)
feedEntry.Title = titleElement.Value;
// ...
Android tip |
---|
For Android apps, the equivalent of the preceding approach is to call the XmlPullParser class's getText method to get the value of the current element. |
Similarly, assign the value of the Link
property to the value of the <link>
element's href
attribute.
// ...
// Get the link.
var linkElement = (from e in entry.Elements(linkXName) select e).FirstOrDefault();
if (linkElement != null)
{
var hrefAttribute = linkElement.Attributes("href").FirstOrDefault();
if (hrefAttribute != null)
{
feedEntry.Link = hrefAttribute.Value;
}
// ...
Android tip |
---|
For Android apps, to get the attribute value, call the XmlPullParser class's getAttributeValue method. |
Next, assign the value of the Summary
property to the value of the <summary>
element, and add the object to the result set to be returned to the calling method.
// ...
var summaryElement = (from e in entry.Elements(titleXName) select e).FirstOrDefault();
if (summaryElement != null)
feedEntry.Summary = summaryElement.Value;
// Add the entry to the result set.
results.Add(feedEntry);
// ...
Finally, call the Parse
method. Since the Parse
method was modified with the async keyword, it can be called asynchronously by using the await operator.
// ...
var parser = new StackOverflowXmlParser();
var entries = await parser.Parse();
// Do something with the entries.
// ...
Top