(X) Hide this
    • Login
    • Join
      • Generate New Image
        By clicking 'Register' you accept the terms of use .

Windows Phone 7 Data Access Strategies: Connection detection and bandwidth

(2 votes)
Andrea Boschin
>
Andrea Boschin
Joined Nov 17, 2009
Articles:   91
Comments:   9
More Articles
4 comments   /   posted on Sep 26, 2011
Categories:   Windows Phone
Tweet This!

When you write a data aware application, where data is not locally accessible but is available across a network connection, you have an additional requirement to ensure the network connection is available and also it is able to transport your data in a reliable way. Working with a mobile device like Windows Phone, these requirements are strong because of the continuous variations of the cellular network availability.

Also, most of the times, you have to choice about using or not an available network, depending on its capabilities and on the data you have to move across the wire.

 

Being aware of the network

When you need to make a connection to the internet, the first check is about the presence of the network. There are two strategies you can adopt for this purpose:

a) You can check for the network connectivity just before sending the request and give an alert to the user. This is best targeted when you need to avoid connection errors for single and atomic transactions. A twitter client is a good example of this scenario, where you can simply stop posting a twit if the network is absent.

b) you can monitor the network and react when it changes it state. This is the case of a smart application where you have to store your data locally and then access the network to make a synchronization with the server database.

Windows Phone support both the scenario with a couple of classes. The first scenario, where you need to ensure the network is available is pretty simple. Using the NetworkInterface class you can get some simple information about the connection. The GetIsNetworkAvailable method returns true or false whether you are connected or not.

 1: bool isThereNetwork = 
 2:     Microsoft.Phone.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable();
 3:  
 4: if (isThereNetwork)
 5: {
 6:     // start your network operation
 7: }
 8: else
 9:     MessageBox.Show("Unable to connect to the network");

Using this method you have to be aware that the USB connection to the laptop is definitely a valid network connection. So, to make a test, you have to deploy the application on the device then disconnect it from the pc. If you do not disconnect the device the GetIsNetworkAvailable method will always return true, no matter if you switch off the network from Windows Phone.

To support the scenario where you have to monitor the connectivity to know when to accomplish a synchronization, you do not need to call the above method on a scheduled basis. Instead you can rely on the NetworkChange class which have a NetworkAddressChanged event, raised when something changes on your connection.

 1: public MainPage()
 2: {
 3:     InitializeComponent();
 4:  
 5:     NetworkChange.NetworkAddressChanged += new NetworkAddressChangedEventHandler(NetworkChange_NetworkAddressChanged);
 6: }
 7:  
 8: void NetworkChange_NetworkAddressChanged(object sender, EventArgs e)
 9: {
 10:     bool isThereNetwork =
 11:         Microsoft.Phone.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable();
 12:  
 13:     message.Text = DateTime.Now.ToLongTimeString() + " - " + (isThereNetwork ? "Network is online" : "Network is offline");
 14: }

The NetworkAddressChanged event does not directly means that your connection has swiched on of off but, as the event name suggests, it means that something has changed of the network interfaces and you should make a test to verify that the network is still available. It is the reason why, in the body of the event handler, I make a test with the GetIsNetworkAvailable method that let me know the real state of the connection.

If you make some tries, switching on the airplane mode and connecting and disconnecting the USB cable to simulate the network unstability, you will observe that, once you reconnect the network there's a couple of events returning back from the NetworkChange class and only the last is raised when the connection is back on. So please plan carefully how to make this check in a reliable way.

Plan for bandwidth

There are for sure situations where, also if a network is available, you cannot use it to deliver the information you need to send to the server. Imagine to have a huge xml file that needs to send a lot of transactions in an atomic way, or an update for a local database that involves the moving of a lot of bytes across the network. In these scenario you need to ensure that the network is not only available but also that it is so much stable and fast to grant a reliable communication to move your data.

As an example you can plan to make the sync only when the device is docked to the laptop so you can rely on a really fast network or also you can wait to have a wi-fi connection and prevent the synchronization tasks to happen during a normal GPRS/UMTS connection.

The NetworkInterface class provides a NetworkInterfaceType property which can be used to know the type of network you are connected to. This property refer to an enumerator that exposes a number of kind of connections. Starting with None, that means no connection available, you can find lot of values like Ethernet (usually when docked), MobileBroadbandGsm (GPRS/EDGE/UMTS/HSDPA/HSPA), Wireless80211 (during wi-fi connections) and so on. The code to retrieve this information may be simple:

 1: private void NetworkChange_NetworkAddressChanged(object sender, EventArgs e)
 2: {
 3:     NetworkInterfaceType interfaceType = NetworkInterface.NetworkInterfaceType;
 4:  
 5:     message.Text = interfaceType.ToString();
 6: }

Unfortunately, as often happens, things are not so easy. The problem here is that the call to NetworkInterfaceType is syncronous and it can take lot of time to return the value. So, is you try to accomplish this task in the UI thread you can freeze the application for a time between 10 and 20 seconds and this is totally wrong. This also imply your applicationwill fail the submission process to the marketplace because the responsivity of the user interface during network operation is a must.

To work around this problem you have to use a separate thread to access the property and then cache locally the required information. Here is a small snippet that use a spawned thread to read NetworkInterfaceType:

 1: private void NetworkChange_NetworkAddressChanged(object sender, EventArgs e)
 2: {
 3:     ThreadPool.QueueUserWorkItem(
 4:         o =>
 5:         {
 6:             try
 7:             {
 8:                 NetworkInterfaceType interfaceType = NetworkInterface.NetworkInterfaceType;
 9:  
 10:                 Deployment.Current.Dispatcher.BeginInvoke(() => this.UpdateNetworkInfo(interfaceType));
 11:             }
 12:             catch (Exception ex)
 13:             {
 14:                 Deployment.Current.Dispatcher.BeginInvoke(() => this.HandleExceptions(ex));
 15:             }
 16:  
 17:         }, null);
 18: }

Using the ThreadPool you will have a number of thread spawned once the network will change its state so you have to carefully plan the access to the shared cached information that will be concurrently written.

Implementing a simple watchdog

Planning for availability and bandwidth have a number of application that may be shared across different softwares. So, once you are aware of the implications of using the API to retrieve these information you can for sure implement a reusable component that simplify the tasks during development.

For this purpose I wrote an application service that you can simply add to the App.xaml, in the LifetimeObjects section, and then attach a single event that notifies about both availability and interface type in an asynchronous and thread safe way. The following box contains all the code of the service I have called NetworkWatchdog:

 1: public class NetworkWatchdog : IApplicationService
 2: {
 3:     private object _lockObj = new object();
 4:     public event EventHandler<NetworkChangedEventArgs> NetworkChanged;
 5:  
 6:     /// <summary>
 7:     /// Gets the current.
 8:     /// </summary>
 9:     public static NetworkWatchdog Current { get; private set; }
 10:     /// <summary>
 11:     /// Gets a value indicating whether this instance is network available.
 12:     /// </summary>
 13:     /// <value>
 14:     /// <c>true</c> if this instance is network available; otherwise, <c>false</c>.
 15:     /// </value>
 16:     public bool IsNetworkAvailable { get; private set; }
 17:     /// <summary>
 18:     /// Gets the type of the interface.
 19:     /// </summary>
 20:     /// <value>
 21:     /// The type of the interface.
 22:     /// </value>
 23:     public NetworkInterfaceType InterfaceType { get; private set; }
 24:  
 25:     /// <summary>
 26:     /// Initializes a new instance of the <see cref="NetworkWatchdog"/> class.
 27:     /// </summary>
 28:     public NetworkWatchdog()
 29:     {
 30:         if (NetworkWatchdog.Current != null)
 31:             throw new Exception("Only a single watchdog is allowed");
 32:  
 33:         NetworkWatchdog.Current = this;
 34:     }
 35:  
 36:     /// <summary>
 37:     /// Called by an application in order to initialize the application extension service.
 38:     /// </summary>
 39:     /// <param name="context">Provides information about the application state.</param>
 40:     public void StartService(ApplicationServiceContext context)
 41:     {
 42:         System.Net.NetworkInformation.NetworkChange.NetworkAddressChanged +=
 43:             new System.Net.NetworkInformation.NetworkAddressChangedEventHandler(NetworkChange_NetworkAddressChanged);
 44:  
 45:         ThreadPool.QueueUserWorkItem(ReadNetworkInformation, null);
 46:     }
 47:  
 48:     /// <summary>
 49:     /// Called by an application in order to stop the application extension service.
 50:     /// </summary>
 51:     public void StopService()
 52:     {
 53:         System.Net.NetworkInformation.NetworkChange.NetworkAddressChanged -=
 54:             new System.Net.NetworkInformation.NetworkAddressChangedEventHandler(NetworkChange_NetworkAddressChanged);
 55:     }
 56:  
 57:     /// <summary>
 58:     /// Handles the NetworkAddressChanged event of the NetworkChange control.
 59:     /// </summary>
 60:     /// <param name="sender">The source of the event.</param>
 61:     /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
 62:     private void NetworkChange_NetworkAddressChanged(object sender, EventArgs e)
 63:     {
 64:         ThreadPool.QueueUserWorkItem(ReadNetworkInformation, null);
 65:     }
 66:  
 67:     /// <summary>
 68:     /// Reads the network information.
 69:     /// </summary>
 70:     /// <param name="state">The state.</param>
 71:     private void ReadNetworkInformation(object state)
 72:     {
 73:         try
 74:         {
 75:             bool isAvailable = NetworkInterface.GetIsNetworkAvailable();
 76:             NetworkInterfaceType interfaceType = NetworkInterface.NetworkInterfaceType;
 77:  
 78:             bool isAvailableChanged = false;
 79:             bool isTypeChanged = false;
 80:  
 81:             lock (_lockObj)
 82:             {
 83:                 if (this.IsNetworkAvailable != isAvailable)
 84:                 {
 85:                     this.IsNetworkAvailable = NetworkInterface.GetIsNetworkAvailable();
 86:                     isAvailableChanged = true;
 87:                 }
 88:  
 89:                 if (this.InterfaceType != interfaceType)
 90:                 {
 91:                     this.InterfaceType = interfaceType;
 92:                     isTypeChanged = true;
 93:                 }
 94:             }
 95:  
 96:             if (isAvailableChanged || isTypeChanged)
 97:                 this.OnNetworkChanged(isAvailableChanged, isTypeChanged);
 98:         }
 99:         catch (Exception ex)
 100:         {
 101:             Deployment.Current.Dispatcher.BeginInvoke(
 102:                 () => MessageBox.Show(ex.ToString()));
 103:         }
 104:     }
 105:  
 106:     /// <summary>
 107:     /// Called when [network changed].
 108:     /// </summary>
 109:     /// <param name="isAvailableChanged">if set to <c>true</c> [is available changed].</param>
 110:     /// <param name="isTypeChanged">if set to <c>true</c> [is type changed].</param>
 111:     private void OnNetworkChanged(bool isAvailableChanged, bool isTypeChanged)
 112:     {
 113:         EventHandler<NetworkChangedEventArgs> handler = this.NetworkChanged;
 114:  
 115:         if (handler != null)
 116:             Deployment.Current.Dispatcher.BeginInvoke(
 117:                 () => handler(this, new NetworkChangedEventArgs(isAvailableChanged, isTypeChanged)));
 118:     }
 119: }
 120:  
 121: public class NetworkChangedEventArgs : EventArgs
 122: {
 123:     /// <summary>
 124:     /// Gets or sets a value indicating whether this instance is availability changed.
 125:     /// </summary>
 126:     /// <value>
 127:     /// <c>true</c> if this instance is availability changed; otherwise, <c>false</c>.
 128:     /// </value>
 129:     public bool IsAvailabilityChanged { get; set; }
 130:     /// <summary>
 131:     /// Gets or sets a value indicating whether this instance is network type changed.
 132:     /// </summary>
 133:     /// <value>
 134:     /// <c>true</c> if this instance is network type changed; otherwise, <c>false</c>.
 135:     /// </value>
 136:     public bool IsNetworkTypeChanged { get; set; }
 137:  
 138:     /// <summary>
 139:     /// Initializes a new instance of the <see cref="NetworkChangedEventArgs"/> class.
 140:     /// </summary>
 141:     /// <param name="isAvailabilityChanged">if set to <c>true</c> [is availability changed].</param>
 142:     /// <param name="isNetworkTypeChanged">if set to <c>true</c> [is network type changed].</param>
 143:     public NetworkChangedEventArgs(bool isAvailabilityChanged, bool isNetworkTypeChanged)
 144:     {
 145:         this.IsAvailabilityChanged = isAvailabilityChanged;
 146:         this.IsNetworkTypeChanged = isNetworkTypeChanged;
 147:     }
 148: }

The work starts with the StartService method where I attach the NetworkChange class notification's. In the symmetric StopService method I detach the same event to avoid unwanted leaks. Every time a network change is detected, and also the first time the service is started, I start a thread in the thread pool. It is in charge of reading the availability and the interface type.

Once these information are read they are cached to two properties that are available to the application to easyli an fast know the current state of the network without the need of reading the NetworkInterfaceType every time. Please be aware that the access to these properties, when a change is detected, is ruled by a lock on and object to prevent invalid concurrent write.

During the reading phase I also collect two boolean values stating about what is changed during the update. IsAvailabilityChanged and IsNetworkTypeChanged are copied to the NetworkChangeEventArgs class that is sent to the attached event handlers. This event notifies the application in a safe way about changes and let the developer know what is changed. The he can use the properties of the service to know the current values.

Conclusion

In this five articles I've deeply explored the tools and the network connectivity scenario about security and availability. Windows Phone is for sure an effective platform that provides a good environment to access resources with a wide set of tools and, as Microsoft usually does,  it is also simple to use. These only a bunch of things you have to take care and it is important you make the right choices.


Subscribe

Comments

  • MisterGoodcat

    Re: Windows Phone 7 Data Access Strategies: Connection detection and bandwidth


    posted by MisterGoodcat on Nov 25, 2011 13:30

    Hi Andrea,

    I came across a problem with this implementation: due to the caching of the network interface and state, the watchdog reports the wrong information on activation, e.g. when the app is returning from tombstoning. Scenario: the last detected connection is a wireless connection, then the application is deactivated (lock screen, for example). After returning to the app, it can take several seconds for the phone to restore a wireless connection (I observed up to 7 seconds on an Omnia 7). During that time, the watchdog still reports a working wireless connection, even though no connection is available.

    I solved that by moving the code from the start/stop service events to the phone application service lifetime events, and by initializing the watchdog to a indeterminate state when the app is activated or launched, i.e. returning a network interface of Unknown and that no network is available, until the first/next reading of that data has finished and the properties can be filled with the actual values.

    Hopefully this is helpful to you or other readers. Thanks for the otherwise great article!

    -Peter

  • AndreaBoschin

    Re: Windows Phone 7 Data Access Strategies: Connection detection and bandwidth


    posted by AndreaBoschin on Nov 26, 2011 22:28
    Hi, you solution is good. Thanks for your notice. Andrea
  • veejay

    Re: Windows Phone 7 Data Access Strategies: Connection detection and bandwidth


    posted by veejay on Nov 06, 2013 11:26

    Thanks for sharing for this great article and requesting you to share us the implementation of NetworkWatchdog wrapper, i am new for developing the windows app and facing some networking issue which you had mentioned over your great article.

  • veejay

    Re: Windows Phone 7 Data Access Strategies: Connection detection and bandwidth


    posted by veejay on Nov 06, 2013 13:26

    Thanks for sharing for this great article and requesting you to share us the implementation of NetworkWatchdog wrapper, i am new for developing the windows app and facing some networking issue which you had mentioned over your great article.

Add Comment

Login to comment:
  *      *       

From this series