Networking Your Windows 8.1 Devices and Apps
Network connectivity is a major feature of most Windows Store apps, as you learned in previous chapters. Although you have learned how to connect to services and keep your content fresh, Windows 8.1 devices are capable of connecting to the Internet and other devices in myriad ways. In this chapter, you learn some of these more advanced methods and how to integrate them into your own apps.
In addition to supporting the HTTP protocols, WinRT provides APIs that make it easy to enumerate resources on your HomeGroup network. You can enumerate network information and obtain the current data plan so that your app can modify its behavior to avoid downloading large amounts of data over a metered connection. The sockets APIs enable low-level communications using traditional UDP and TCP protocols, as well as the newer HTML5 WebSockets protocol. The proximity APIs enable communications between peer devices using Near Field Communications (NFC) and Wi-Fi Direct. Finally, the background transfer API allows your app to effectively manage long-running data transfers even when the app itself is not running.
Web and HTTP
In Chapter 5, “Web Services and Syndication,” you learned how to use the HttpClient class to connect to an HTTP server and retrieve content using the REST architecture. The Windows.Web.Http namespace contains several classes that you can use to connect with HTTP-based services. The HttpClient class represents a simple and easy-to-use interface for sending HTTP-related requests and retrieving responses. Other classes provide more advanced features and fine-grained control over interactions.
To provide more control over HTTP requests, use the HttpRequestMessage class. For example, the following requests content from my blog:
var client = new HttpClient(); var httpResponse = await client.GetAsync(new Uri( "http://csharperimage.jeremylikness.com/", UriKind.Absolute));
If you want more control over the type of request and process the request immediately after the headers have been read (instead of having to wait for the entire body), you can issue the request like this instead:
var client = new HttpClient(); var request = new HttpRequestMessage( HttpMethod.Get, new Uri("http://csharperimage.jeremylikness. com")); var response = await client.SendRequestAsync(request, HttpCompletionOption.ResponseHeadersRead);
Using the latter method also gives you more control over the response. You can create a cancellation token and convert the response to a Task that uses the token:
this.cancellation = new CancellationTokenSource(); var response = await client.SendRequestAsync( request, HttpCompletionOption.ResponseHeadersRead) .AsTask(cancellation.Token);
When the page takes a significant time to load, from either a slow network or a large amount of information, you can cancel the load automatically or through user input by calling the cancel method on the cancellation token. You see an example of this in the CancelUrl method of the ViewModel class in the AdvancedHttpExample project:
cts.Cancel(); cts.Dispose();
The project enables you to enter a URL and then downloads and displays the content. The initial request ends when the headers are received so that you can stream the content with progress updates. You can cancel longer-running downloads and watch the progress. The content is exposed through the Content property of the HttpResponseMessage that is returned. The LoadUrl method demonstrates creating a progress handler that takes a type ulong and asynchronously downloads the content as a string.
this.progress = new Progress<ulong>(ProgressHandler); var stringContent = await response.Content .ReadAsStringAsync().AsTask(cancellation.Token, this.progress);
The progress handler is passed the number of bytes received and uses the dispatcher to set them as a property on the viewmodel to show the progress to the user.
private void ProgressHandler(ulong progressArgs)
If you use the default URL of my blog, the content loads immediately and the progress method never gets called. Using a longer URL, such as the URL to a large book such as Ulysses in HTML format from the Gutenberg project, results in a longer download and progress updates. The URL, listed in the source of the viewmodel, to make it easy for you to copy, is www.gutenberg.org/files/4300/4300-h/4300-h.htm.
You can also use the request message to post content, including streams, to the server. The Content property of the HttpRequestMessage can be assigned any instance that implements IHttpContent. This includes the following content:
- HttpBufferContent—Content that uses an IBuffer instance
- HttpFormUrlEncodedContent—Content that uses name/value pairs for a form post
- HttpJsonContent—Content that is represented using the JSON format
- HttpMultipartContent—Content that uses the multipart MIME type for uploading multiple attachments
- HttpMultipartFormDataContent—A special format for forms encoded using the multipart/form-data MIME type
- HttpStreamContent—Content that uses a stream, such as when uploading files to the server
- HttpStringContent—Content that uses a string
The HTTP API also provides the HttpProgress class for tracking and handling the progress of long-running HTTP uploads. Simply create an instance of the progress handler and pass it to the extension method that converts the call to a Task:
var progress = new Progress<HttpProgress>(ProgressHandler); HttpResponseMessage response = await httpClient.PostAsync( resourceAddress, streamContent).AsTask(cts.Token, progress);
The signature of the handler is a simple method that takes an instance of HttpProgress and can query items such as bytes sent versus total bytes sent, number of retries, and the stage of the process (for example, sending or receiving content).