Contents
This article describes a small class that can be used to determine network availability and detect when changes occur in connectivity. This focuses on "Internet availability". In other words, if at least one IP related interface is available and working, then we assume the "network" is available.
The iTuner lyrics engine relies on online providers to search for song lyrics. It reaches out to the Internet whenever a song that does not yet have lyrics begins playing. Requirements specific to iTuner are as follows:
- Determine the current connectivity state
- Subscribe to be notified when changes occur in network connectivity
- Ignore all network adapters that probably do not provide connectivity to the Internet since my main goal was to contact Internet resources
This led to the System.Net.NetworkInformation
namespace and the thin wrapper presented below. There are a couple of scenarios that these System
classes do not cover and this article addresses those. Of course, you could generalize these requirements for any application or extend this class with other features such as pinging a target site to check for existence prior to heavier communication.
The NetworkStatus
class is a static
class exposing one method and one event as shown here:
public static class NetworkStatus
{
public static event NetworkStatusChangedHandler AvailabilityChanged;
public static bool IsAvailable { get; }
}
As you can see, there's not much to it - and that's the point. Although there's not an immense amount of code behind this class, it encapsulates all the messiness so we don't have to worry about the details. The NetworkStatusDemo
application attached to this article demonstrates the most minimal use of this class. It first reports the current network availability using the IsAvailable
property.
if (NetworkStatus.IsAvailable)
{
Console.WriteLine("... Network is available");
}
else
{
Console.WriteLine("... Network is not available");
}
NetworkStatusDemo
then attaches a NetworkStatusChangedHandler
handler to the AvailabilityChanged
event.
NetworkStatus.AvailabilityChanged +=
new NetworkStatusChangedHandler(DoAvailabilityChanged);
static void DoAvailabilityChanged (
object sender, NetworkStatusChangedArgs e)
{
if (e.IsAvailable)
{
Console.WriteLine("... Network is available");
}
else
{
Console.WriteLine("... Network is not available");
}
}
Quite simple, but it's enough to determine whether we should attempt to contact a Web site or Web service at any specific point in time.
While the original .NET classes provide most of the functionality needed here, I had two primary objectives:
- Narrow the scope of the
NetworkInterface
class to only report on adapters capable of connecting to the Internet
- Encapsulate the multiple events offered by the
NetworkChange
class
The NetworkInteface
class includes the static GetIsNetworkAvailable()
method. While this method already does most of the work we need, I've found there are situations, especially with wireless adapters, where the network appears to be online but has not yet established a truly open connection to the network. It also sees virtual machine adapters and thinks they are online; obviously, unless you've some strange development configuration where you're using a virtual machine as a router, these are not going to lead you to the Internet.
We begin with a quick test using GetIsNetworkAvailable
but then extend that by examining each appropriate network interface for activity, BytesReceived
and BytesSent
. This is encapsulated in our NetworkStatus.IsNetworkAvailable()
method.
private static bool IsNetworkAvailable ()
{
if (NetworkInterface.GetIsNetworkAvailable())
{
NetworkInterface[] interfaces =
NetworkInterface.GetAllNetworkInterfaces();
foreach (NetworkInterface face in interfaces)
{
if (face.OperationalStatus == OperationalStatus.Up)
{
if ((face.NetworkInterfaceType != NetworkInterfaceType.Tunnel) &&
(face.NetworkInterfaceType != NetworkInterfaceType.Loopback))
{
IPv4InterfaceStatistics statistics =
face.GetIPv4Statistics();
if ((statistics.BytesReceived > 0) &&
(statistics.BytesSent > 0))
{
return true;
}
}
}
}
}
return false;
}
While this is sufficient to test for current availability, we can optimize efficiency by maintaining a private Boolean
variable, isAvailable
, and setting its state only when the connectivity status changes. This is where the NetworkChange
class comes into play.
The NetworkChange
class has two events, NetworkAvailabilityChanged
and NetworkAddressChanged
. Sounds great. But the problem is that NetworkChange
does not discriminate against adapters that might not grant us access to the Internet, such as tunnel adapters. So our NetworkStatus
class extends this capability to include events from only relevant adapters. We manage this by tightly controlling the NetworkAvailabilityChanged
and NetworkAddressChanged
events ourselves, hiding them behind our own AvailabilityChanged
event.
public static event NetworkStatusChangedHandler AvailabilityChanged
{
add
{
if (handler == null)
{
NetworkChange.NetworkAvailabilityChanged
+= new NetworkAvailabilityChangedEventHandler(
DoNetworkAvailabilityChanged);
NetworkChange.NetworkAddressChanged
+= new NetworkAddressChangedEventHandler(
DoNetworkAddressChanged);
}
handler = (NetworkStatusChangedHandler)Delegate.Combine(handler, value);
}
remove
{
handler = (NetworkStatusChangedHandler)Delegate.Remove(handler, value);
if (handler == null)
{
NetworkChange.NetworkAvailabilityChanged
-= new NetworkAvailabilityChangedEventHandler(
DoNetworkAvailabilityChanged);
NetworkChange.NetworkAddressChanged
-= new NetworkAddressChangedEventHandler(
DoNetworkAddressChanged);
}
}
}
You can see that we provide our own handler
variable. This is defined as an event that we can fire when we want to signal state changes to our consumers.
Unfortunately, the handlers for the two wrapped events do not have similar signatures. So we need to supply two distinct handlers. But they both funnel into a single point, SignalAvailabilityChange
.
private static void SignalAvailabilityChange (object sender)
{
bool change = IsNetworkAvailable();
if (change != isAvailable)
{
isAvailable = change;
if (handler != null)
{
handler(sender, new NetworkStatusChangedArgs(isAvailable));
}
}
}
In the end, not a lot of code and not very complicated or revolutionary. But it's proven to be a tidy implementation that helps to simplify any main application.
If you found this article helpful and enjoy the iTuner application, please consider donating to support continual improvements of iTuner and, hopefully, more helpful articles. Thanks!