560 likes | 656 Vues
Windows Phone 8 Networking Survival Kit. Andy Wigley Microsoft UK. Session Objectives And Takeaways. Session Objective(s ): Use async and await for HTTP programming Make smart decisions about data transfer Use Compression on Windows Phone Store Files in SkyDrive
E N D
Windows Phone 8 Networking Survival Kit Andy Wigley Microsoft UK
Session Objectives And Takeaways Session Objective(s): Use async and await for HTTP programming Make smart decisions about data transfer Use Compression on Windows Phone Store Files in SkyDrive Access local services from the Emulator Program Bluetooth applications Implement NFC ‘Tap to Share’ features in your apps Be a Windows Phone Networking Guru! Build Great Windows Phone Networked Applications
Async Support in WP8 Networking APIs C# 5.0 includes the async and await keywords to ease writing of asynchronous code In Windows Store Apps, new Task-based methods exclusively used for networking, not supported on Windows Phone 8 HttpClientAPI HttpWebRequest.GetResponseAsync() Workarounds are available: Async with WebClient possible using extension methods Async with HttpWebRequestpossible using extension methods or TaskFactory.FromAsync<T>
HTTP Networking withoutAsync usingSystem.Net; ... WebClient client; publicMainPage() { ... client = newWebClient(); client.DownloadStringCompleted += client_DownloadStringCompleted; } voidclient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) { this.downloadedText = e.Result; } privatevoidloadButton_Click(object sender, RoutedEventArgs e) { client.DownloadStringAsync(newUri("http://MyServer/ServicesApplication/rssdump.xml")); }
Http Networking withAsync usingSystem.Net; usingSystem.Threading.Tasks; ... privateasyncvoidLoadWithWebClient() { var client = newWebClient(); string response = awaitclient.DownloadStringTaskAsync( newUri("http://MyServer/ServicesApplication/rssdump.xml")); this.downloadedText = response; } privateasyncvoidLoadWithHttpWebRequest() { HttpWebRequestrequest = (HttpWebRequest)WebRequest.Create("http://services.odata.org/Northwind/Northwind.svc/Suppliers"); request.Method= HttpMethod.Get; HttpWebResponseresponse = (HttpWebResponse)awaitrequest.GetResponseAsync(); ... }
Using HttpClient //Following requiresHttpClient.CompressionNuGet package var handler = newAdvancedREI.Net.Http.Compression.CompressedHttpClientHandler(); // Create the HttpClient HttpClienthttpClient = newHttpClient(handler); // To use without compression support (but why do that?), use default HttpClient constructor // without the compression handler: HttpClienthttpClient = new HttpClient(); // Optionally, define HTTP headers httpClient.DefaultRequestHeaders.Add("Accept", "application/json"); // Make the call HttpResponseMessage response = awaithttpClient.GetAsync( "http://services.odata.org/Northwind/Northwind.svc/Suppliers"); response.EnsureSuccessStatusCode(); // Throws exception if bad HTTP status code stringresponseBodyAsText = awaitresponse.Content.ReadAsStringAsync();
HTTP Networking using Async Andy Wigley
Network Awareness Making Decisions based on Data Connections Mobile apps shouldn’t diminish the user experience by trying to send or receive data in the absence of network connectivity Mobile apps should be intelligent about performing heavy data transfers only when the appropriate connectivity is available Use the NetworkInterfaceType object to detect network type and speed Subscribe to the NetworkChange event to detect when the network state changes 12
NetworkInformation in Windows Phone 8.0 • In Microsoft.Phone.Net.NetworkInformation namespace: • Determine the Network Operator: • DeviceNetworkInformation.CellularMobileOperator • Determine the Network Capabilities: • DeviceNetworkInformation.IsNetworkAvailable • DeviceNetworkInformation.IsCellularDataEnabled • DeviceNetworkInformation.IsCellularDataRoamingEnabled • DeviceNetworkInformation.IsWiFiEnabled • In Windows.Networking.Connectivity namespace: • Get Information about the current internet connection • NetworkInformation.GetInternetConnectionProfile
Determining the Internet Connection Type privateconstint IANA_INTERFACE_TYPE_OTHER = 1;privateconstint IANA_INTERFACE_TYPE_ETHERNET = 6;privateconstint IANA_INTERFACE_TYPE_PPP = 23;privateconstint IANA_INTERFACE_TYPE_WIFI = 71;...string network = string.Empty; // Get current Internet Connection Profile.ConnectionProfileinternetConnectionProfile = Windows.Networking.Connectivity.NetworkInformation.GetInternetConnectionProfile(); if (internetConnectionProfile != null) // if ‘null’, we are offline. {switch(internetConnectionProfile.NetworkAdapter.IanaInterfaceType) {caseIANA_INTERFACE_TYPE_OTHER: cost += "Network: Other"; break;caseIANA_INTERFACE_TYPE_ETHERNET: cost += "Network: Ethernet"; break;caseIANA_INTERFACE_TYPE_WIFI: cost += "Network: Wifi\r\n"; break;default: cost += "Network: Unknown\r\n"; break; } }
Tips for Network Efficiency Mobile devices are often connected to poor quality network connections Best chance of success in network data transfers achieved by: Keep data volumes as small as possible Use the most compact data serialization available (use JSON instead of XML) Avoid large data transfers Avoid transferring redundant data Design your protocol to only transfer precisely the data you need and no more
Wire Serialization Andy Wigley
Wire Serialization Affects Payroll Size • Simple test case: download 30 data records • Each record just 12 fields • Measured bytes to transfer
Implementing Compression WP8 SDK does not include System.IO.Compression.GZipStream Use third-party solutions instead SharpZipLib is a popular C# compression library (http://sharpziplib.com/) – on NuGet SharpCompress is another (http://sharpcompress.codeplex.com/) GZipWebClient available from NuGet Drop-in replacement for WebClient, but adds support for compression Uses SharpZipLib internally
HttpWebRequest – With Compression var request = HttpWebRequest.Create("http://yourPC:15500/NorthwindDataService.svc/Suppliers") asHttpWebRequest; request.Accept= "application/json"; request.Method= HttpMethod.Get; request.Headers["Accept-Encoding"] = "gzip"; HttpWebResponseresponse = (HttpWebResponse)awaitrequest.GetResponseAsync(); // Read the response into a Stream object. System.IO.StreamresponseStream = response.GetResponseStream(); stringdata; varstream = newGZipInputStream(response.GetResponseStream()); using(var reader = newSystem.IO.StreamReader(stream)) { data = reader.ReadToEnd(); } responseStream.Close();
Compression with OData Client Library privatevoidEnableGZipResponses(DataServiceContextctx) { ctx.WritingRequest += newEventHandler<ReadingWritingHttpMessageEventArgs>( (_, args) => { args.Headers["Accept-Encoding"] = "gzip"; } ); ctx.ReadingResponse += newEventHandler<ReadingWritingHttpMessageEventArgs>( (_, args) => { if (args.Headers.ContainsKey("Content-Encoding") && args.Headers["Content-Encoding"].Contains("gzip")) { args.Content = newGZipStream(args.Content); } } ); } Reference: http://blogs.msdn.com/b/astoriateam/archive/2011/10/04/odata-compression-in-windows-phone-7-5-mango.aspx
Configuring Dynamic Content Compression in IIS8 - 1 Enable Dynamic Content Compression in Turn Windows Features on or off
Configuring Dynamic Content Compression in IIS8 - 2 In IIS Manager, select the top line – the Server In Features View, open Compression in IIS Features Check Enable Dynamic Content Compression
Configuring Dynamic Content Compression in IIS8 - 3 In Features View, scroll down to bottom, open Configuration Editor Expand System.Webserver Select httpCompression Add the following new items to the dynamicTypes collection, all with enabled=True application/atom+xml application/atom+xml;charset=utf8 application/json application/json;odata=verbose
Monitoring Traffic with Fiddler Configure Fiddler as a reverse proxy: Start Fiddler, then on the Tools menu, click Fiddler Options On the Connections tab, check Allow remote computers to connect. Click OK. On the Rules menu, click Customize Rules… Add the following to the end of the OnBeforeRequest method: // Re-route connections from remote hosts to port 80 if (oSession.host.toLowerCase() == "yourpc:8888") oSession.host= "yourpc:80"; Replace yourpc with the name of your PC Open port 8888 in your firewall In the Windows Phone client app, change the service URL to http://yourPC:8888/... So that the requests are routed via Fiddler.
Compression Andy Wigley
Windows Phone 8 Emulator and localhost InWindows Phone 7.x, the emulator shared the networking of the Host PC You could host services on your PC and access them from your code using http://localhost ... In Windows Phone 8, the emulator is a Virtual machine running under Hyper-V You cannot access services on your PC using http://localhost ... You must use the correct host name or raw IP address of your host PC in URIs
Configuring Sites Running in IIS Express STEP 1: Create Your Website or Web service Create your website or web service in Visual Studio 2012 Run it and it is configured to run in localhost:port
Configuring Sites Running in IIS Express STEP 2: Modify Config to Run on a URI Using Your PC Name Remove your website (don’t delete!) from the Visual Studio 2012 solution Edit the file C:\Users\yourUsername\Documents\IISExpress\config\applicationhost.config Find the <sites> section Find the entry for the website or service you just created Change<binding protocol="http" bindingInformation="*:18009:localhost" />to<binding protocol="http" bindingInformation="*:18009:YourPCName" /> Save changes Use ‘Add Existing Website’ to add the website folder back into your solution Run it and access from your desktop browser – Now it is hosted at YourPCName:18009
Configuring Sites Running in IIS Express STEP 3: Open Port in the Firewall and Register URL From a Command Prompt (Run as Administrator), open the port in the Firewall:netshadvfirewall firewall add rule name="IIS Express (non-SSL)" action=allow protocol=TCP dir=in localport=8080 Also run the following at the command prompt:netsh http add urlaclurl=http://yourPC:8080/ user=everyone Substitute yourPCwith the host name of your Host PC Substitute 8080for the port where your service is running Useful References: How to: Specify a Port for the Development Server http://msdn.microsoft.com/en-us/library/ms178109(v=VS.100).aspx
Accessing local services from the emulator Andy Wigley
Local Communication with WP8 Local Communication is new to Windows Phone 8 In Windows Phone 7 processes had to communicate using network connections This was difficult because programs had to determine the required IP address In Windows Phone 8 there are two new local communication methods available: Bluetooth Can be used for phone to phone and phone to device communication over a range of up to 10 meters Near Field Communication (NFC) Can be used for phone to device communication in very close proximity
Bluetooth Scenarios Bluetooth is a short range wireless communication technology Nominally the range is up to 10 metres, but this can be reduced by the conditions Two Bluetooth communication scenarios supported: App to device A program running on a Windows Phone can establish a connection to an external device The Windows Phone must be paired with the device App to app A program running on a Windows Phone can find another application that is offering a service that the device wishes to use In this situation pairing is not required The Bluetooth connection is provided to the program in the form of a StreamSocket
App to Device An application running on a Windows Phone 8 device can obtain an enumeration of all the Bluetooth devices that have been paired with the phone The application can then attempt to make a connection to the required service on that device The ID_CAP_PROXIMITY and ID_CAP_NETWORKING capabilities must be enabled for the application to make use of the Bluetooth communications to a device
Bluetooth Pairing For App-to-Device scenarios, the device must have been paired with the phone A device must be made “discoverable” before pairing can take place Pairing is normally performed via the settings screen on the device During the pairing the connection is authenticated The user may need to enter a key to validate the connection This may be a fixed key, as in the case of devices such as headsets, or generated by one device and entered on the other In an App-to-App Bluetooth connection, one app is looking for another instance of itself on another phone Can communicate without needing to be paired
Finding Paired devices The PeerFinder class can be used to search for paired devices The search will fail with the exception shown above if Bluetooth is switched off try { PeerFinder.AlternateIdentities["Bluetooth:Paired"] = ""; var peers = awaitPeerFinder.FindAllPeersAsync(); } catch (Exception ex) { if ((uint)ex.HResult == 0x8007048F) MessageBox.Show("Bluetooth is switched off"); }
App to App communication App to App communication allows two programs to interact using Bluetooth to exchange messages An application can wait for and respond to messages from another application The PeerFinder class exposes an event which is raised when a communication request is received from another system The communication is still performed using a SocketStream that links the two programs The devices do not need to be paired in order to implement app to app connection The ID_CAP_PROXIMITY capability must be enabled
Advertising a Bluetooth Service An application can advertise itself as accepting connections by setting the display name for the PeerFinder and then starting to advertise the service Note that doing this for a long time may have an adverse effect on battery life This task can also be used to provide quick access to other settings // Register for incoming connection requests PeerFinder.ConnectionRequested += PeerFinder_ConnectionRequested; // Start advertising ourselves so that our peers can find us PeerFinder.DisplayName = "TicTacToe BT"; PeerFinder.Start();
Waiting for an Incoming Connection // Register for incoming connection requests PeerFinder.ConnectionRequested += PeerFinder_ConnectionRequested; // Start advertising ourselves so that our peers can find us PeerFinder.DisplayName = "TicTacToe BT"; PeerFinder.Start(); An application can subscribe to the ConnectionRequested event When the event fires the application can then decide whether to accept the request It could display a confirmation dialog to the user This task can also be used to provide quick access to other settings
Responding to a Connection Request The above method creates a connection to an incoming request from “RobsPhone” It uses the PeerInformation property of the ConnectionRequestedEventArgs to determine who is attempting to connect This task can also be used to provide quick access to other settings StreamSocket socket; asyncvoidPeerFinder_ConnectionRequested(object sender, ConnectionRequestedEventArgsargs) { if ( args.PeerInformation.DisplayName == "RobsPhone" ) { socket = awaitPeerFinder.ConnectAsync(args.PeerInformation); PeerFinder.Stop(); } }
Bluetooth communication Andy Wigley
Near Field Communications NFC provides a connection between devices that are very close together (within 3-4 centimetres) The data is transferred at a rate of up to 424 Kbits/second It is assumed that this data transfer is intentional so there is not normally any authentication as such The user has positioned their device close to the other device The phone can connect to an unpowered NFC chip/tag
Using Near Field Communications NFC is best for sending small amounts of data between devices and can be used in a number of different scenarios: Connect devices Initiate a Bluetooth or WiFi (Infrastructure) connection to your app on another device Acquire content Read “smart” posters that contain digital content in an embedded NFC tag Exchange digital objects Exchange an electronic business card, or vCard.
Using NFC in applications There are two ways that an application can use NFC Simple transfer of a message from one device to another An application can subscribe to message events and receive a string message of a particular type An NFC connection can be used to configure a connection which is implemented using Bluetooth or WiFi This extends the PeerFinder to allow an application to use NFC to quickly set up a StreamSocket between two devices
Programming NFC Tap To Connect In this usage, the PeerFinder class is used to search for other instances of itself on the tapped device ProximityDevice device = ProximityDevice.GetDefault(); // Make sure NFC is supported if (device != null) { PeerFinder.TriggeredConnectionStateChanged += OnTriggeredConnectionStateChanged; // Start finding peer apps, while making this app discoverable by peers PeerFinder.Start(); }
Finding a Windows 8 Peer App using NFC Set the PeerFinder.AlternateIdentities property to allow connections to the Windows 8 version of your app ProximityDevice device = ProximityDevice.GetDefault(); // Make sure NFC is supported if (device != null) { PeerFinder.TriggeredConnectionStateChanged += OnTriggeredConnStateChanged; // Include the Windows 8 version of our app as possible peer PeerFinder.AlternateIdentities.Add("Windows", "my Win8 appID"); // Start finding peer apps, while making this app discoverable by peers PeerFinder.Start(); }
Setting up a StreamSocket using NFC The event arguments contain a state change message voidOnTriggeredConnStateChanged(object sender, TriggeredConnectionStateChangedEventArgsargs) { switch (args.State) { caseTriggeredConnectState.Listening: // Connecting as host break; caseTriggeredConnectState.PeerFound: // Proximity gesture is complete – setting up link break; caseTriggeredConnectState.Connecting: // Connecting as a client break; caseTriggeredConnectState.Completed: // Connection completed, get the socket streamSocket = args.Socket; break; caseTriggeredConnectState.Canceled: // ongoing connection cancelled break; caseTriggeredConnectState.Failed: // Connection was unsuccessful break; } }