At the recent Build developer conference in San Francisco I presented a session on networking in Windows Phone 8. Part of the session was about using the Proximity APIs to cover peer-to-peer scenarios like multiplayer gaming, but the first half was dedicated to more traditional networking APIs – in particular, HTTP and sockets. Here I cover much of the same ground as in the talk, which you also can watch online. You can download the accompanying source code from MSDN: HTTP and Socket API Examples for Windows Phone 8 and WebApi Sample for Windows Phone 8.
Although this blog post and the accompanying sample code are specific to Windows Phone 8, Windows 8 shares the same APIs and the core code works on both platforms. The sample app simply uses a WebBrowser control and then allows you to load a given webpage via one of the four different APIs covered in this post:
Development machine setup
If you’ll be testing a Windows Phone app that communicates with a web service that runs on your local development machine, some additional setup is required. Unlike Windows 8 or Windows Phone 7.1, you can’t just use localhost to refer to the host machine because the Windows Phone 8 emulator is a full Hyper-V virtual machine running on your computer. So in the emulator, localhost refers to the emulator itself, not to the host machine. For detailed instructions about how to set up your development machine, see the MSDN documentation, but here’s a quick summary:
- Determine the IP address of the virtual adapter for your NIC (Wi-Fi or Ethernet) using ipconfig.
- Open %userprofile%\Documents\IISExpress\config\applicationhost.config, find the configuration section for your web project, and then copy-and-paste the
element and replace localhost with your IP address. Note the port number in use. - At an elevated command prompt, run:
netsh http add urlacl url=http://your.ip.address:the_port_number/ user=everyone - At an elevated command prompt, run:
netsh advfirewall firewall add rule dir=in action=allow protocol=tcp localport=the_port_number remoteip=localsubnet profile=private,domain name=friendly_name_of_rule
Displaying HTML content
If all you need to do in your app is show HTML content, either content that’s downloaded from the network or that’s contained in your app package, the WebBrowser control is the easiest solution to use. Showing a static page is easy in XAML:
<phone:WebBrowserx:Name="browserControl"
Source="http://buildwindows.com/"/>
Navigating to a different HTML document in code also is easy:
browserControl.Navigate(uri);
The WebBrowser control supports most features that the stand-alone Internet Explorer browser supports, including showing images, running scripts (if enabled), and following hyperlinks. The control supports pinch-to-zoom, which even works on the emulator if you have a touch-screen monitor. In Windows Phone 8, the control has GoForward and GoBack methods, which were not present in earlier releases.
One caveat with the WebBrowser control: If you’re going to inject HTML using the NavigateToString method, make sure to remove the tags first and include a
Managed HTTP uploads and downloads
If you need to access HTTP resources with managed code, you should use the new HttpClient portable library which you can install using the Project -> Manage NuGet Packages command. To install the HttpClient library you need to be running an up-to-date version of NuGet package manager – if you’re using Visual Studio 2013 Preview on Windows 8.1 Preview it should work as expected, but if you’re using Visual Studio 2012 make sure you first check for updates using the Tools -> Extensions and Updates menu option to make sure NuGet is up to date.
Note that although the old WebClient and HttpWebRequest APIs are still supported in Windows Phone 8, the new HttpClient library is preferred because it’s portable to Windows 8 and has a clean, modern, asynchronous API based on the await pattern.
Retrieving textual data from an HTTP GET method is very easy:
var client = newHttpClient();
var data = await client.GetStringAsync(uri);
Typically you would use this to read XML or JSON data from a web service, or to download HTML that you need to pre-process before sending to the WebBrowser control. You can also retrieve the contents as a Stream or a Byte array, and there are many features for modifying headers, uploading data as a POST or a PUT, and so forth. If you need to read the returned headers or to have more control over how you receive the data, you can use the more advanced APIs that provide access to the HttpResponseMessage. And best of all, you can inject your own code into the HTTP processing pipeline by implementing your own HttpMessageHandler.
Web API and plugging into the HttpClient pipeline
The Build presentation also includes a more realistic sample that uses HttpClient across three platforms (Windows 8, Windows Phone 8, and ASP.NET). The sample includes all the apps in a single project. You can find lots of documentation about the Web API at the ASP.NET site, so we won’t discuss it in detail here.
To use the Web API client extensions, you need to add them using the Project ->Manage NuGet Packages menu item (just like HttpClient) but you also need to include prerelease packages:
The important things to note about this sample are:
1) Before running the project, add the IP address of your computer in WebApiClient_Portable\PhonesClient.cs (it’s easy to find because it will cause a build error).
2) To get the service running before you start the phone or desktop apps, right-click the WebApiTest project and then click View in Browser (your-preferred-browser).
3) Although the WebApiTest solution is quite large, the only custom code is in Controllers\PhonesController.cs; everything else is just the standard project template.
After the service is running, you can use either the Windows Phone 8 app or the Windows Store app to view phones, add phones, or delete them.
To see the custom HttpMessageHandler in action, update the ShowKittens property in WebApiClient_WindowsPhone\MainPage.xaml.cs (it’s easy to find because it will cause a build warning). When ShowKittens is enabled, the sample will return kitten-related data for the first item in the list (the Yellow Nokia Lumia 920) instead of requesting the real data from the network. Although this is a contrived example, it illustrates one of the powerful features of the Web API – that it can mock the client from the server, and vice versa.
Native HTTP uploads and downloads
If you need to access HTTP resources with C or C++, you must use the IXMLHTTPRequest2 interface. The underlying code to use this interface is too complex to show in this blog post, but the sample code provided (which is derived from another MSDN sample) gives you a simple async wrapper to use to get strings:
IAsyncOperation<String^>^ NativeHttpClient::GetStringAsync(Uri^ uri)
{
return create_async([this, uri] {
return m_request.GetAsync(uri).then([](std::wstring html) {
returnrefnew Platform::String(html.c_str());
}); });
}
You can call this from managed code, which looks surprisingly familiar:
var client = newNativeHttpClient();
var data = await client.GetStringAsync(uri);
There’s no reason why you’d use this from managed code (rather than using the HttpClient API) unless you need to perform some of your own native processing at the IXMLHTTPRequest2 layer, for example, reusing some legacy code. In general, if you need to do native networking you can either reuse your existing code or adapt the MSDN sample.
Sockets-based networking
For non-HTTP scenarios, you can use stream-based or datagram-based sockets. Although Windows Phone supports both Winsock (for native code) and System.Net.Sockets (for managed code), the preferred API is Windows.Networking.Sockets because, just like HttpClient, it’s portable to Windows 8, and it exposes a simple, modern, asynchronous API.
The sample code for this blog post demonstrates the basic use of StreamSocket to build a very simplistic HTTP user agent:
var socket = newStreamSocket();
var writer = newDataWriter(socket.OutputStream);
var reader = newDataReader(socket.InputStream);
await socket.ConnectAsync(newHostName(uri.Host), "80");
writer.WriteString(String.Format("GET {0} HTTP/1.1\r\nHost: {1}\r\n\r\n",
uri.AbsolutePath, uri.Host));
await writer.StoreAsync();
// DO NOT DO THIS IN REAL CODE!
var bytesRead = await reader.LoadAsync(300000);
var response = reader.ReadString(bytesRead);
var payloadStart = response.IndexOf("\r\n\r\n");
var data = response.Substring(payloadStart + 4);
socket.Dispose();
This code is simplistic for demonstration purposes; it doesn’t handle errors, content negotiation, redirects, large payloads, and so on. The URL provided in the sample app works at this time, but that could change at any time if the wiki page is edited. This is just a very basic example of the use of sockets via the ConnectAsync method and the DataReader and DataWriter APIs. Typically, if you were doing HTTP-based networking you would use a dedicated HTTP API (like HttpClient); you would only use sockets if the particular app required it, for example, an app that uses streaming media, or a multiplayer game.
Windows Phone provides several different APIs for high-level HTTP access and for lower-level socket access. Although the platform contains several legacy APIs you can use to work with earlier releases, the recommended APIs to use are the HttpClient and IXMLHTTPRequest2 APIs for managed and native HTTP, and the WinRT Sockets API for lower-level access in managed and native code.