Simple Network Status Monitor Example






4.90/5 (15 votes)
Shows how to implement a system to generate events when network interfaces change.
Introduction
I was disappointed to discover nothing in the .NET Framework that generated events when network interfaces became active or inactive. If you are writing a program that requires an active network connection, it can be very useful to be able to respond to changes in the available networks.
Background
The .NET Framework does give some useful information about the network interfaces connected to the system in the System.Net.NetworkInformation
namespace.
Most notably, the NetworkInterface
class. This class contains a static method GetAllNetworkInterfaces()
, that returns an array of NetworkInterface
objects,
populated with information about the available network adapters on your machine.
Note that repeated calls to the GetAlllNetworkInterfaces()
method always returns references to the same classes.
Thus if you keep a reference to a network interface, then call GetAllNetworkInterfaces()
and find the same adapter, and compare the operational-status properties
of the two; even if the network adapter connected or disconnected between the two calls, the operational status properties will be identical, because you are comparing the same object.
So to be able to test the difference between two calls to the GetAllNetworkInterfaces()
method, another object will need to be populated with the values
of the properties from the first call. This object can then be compared to the current values and a difference can be detected.
To be able to raise events when a network interface changes, we need a task that is repeatedly recording the results of GetAllNetworkInterfaces()
,
waiting a defined time, then comparing the current results of GetAllNetworkInterfaces()
, and raising the appropriate events.
Using the code
The attached project defines two important classes: NetworkStatus
and NetworkStatusMonitor
.
NetworkStatus
This serves as a record of the network-interface status(es) for the local machine at the time it was constructed; it keeps its own copies of the NetworkInterface
class' properties.
It defines an inner-class that is the actual record of a network interface status, and keeps a collection of these classes.
/// <summary>
/// keeps a record of a network interface status.
/// </summary>
public class NiStatusRecord
{
/// <summary>
/// construct the network interface status record.
/// </summary>
/// <param name="ni"></param>
public NiStatusRecord(NetworkInterface ni)
{
Interface = ni;
OperationalStatus = ni.OperationalStatus;
Type = ni.NetworkInterfaceType;
Speed = ni.Speed;
}
/// <summary>
/// the network interface
/// </summary>
public NetworkInterface Interface { get; set; }
/// <summary>
/// the recorded operational status of the network interface
/// at the time this class was constructed.
/// </summary>
public OperationalStatus OperationalStatus { get; set; }
/// <summary>
/// the recorded type of the network interface
/// at the tine this class was constructed.
/// </summary>
public NetworkInterfaceType Type { get; set; }
/// <summary>
/// the recorded speed of the network interface
/// at the time this class was constructed.
/// </summary>
public long Speed { get; set; }
}
The NetworkStatus
class also implements a number of methods to compare itself against another instance of the NetworkStatus
class.
These return IEnumerable
s that the network status monitor class uses to figure out which interfaces have changed:
/// <summary>
/// get an enumerable of network interfaces that have connected
/// since the last status. this includes "UP" adapters that
/// were not present in the last test.
/// </summary>
/// <param name="lastStatus">the last NetworkStatus test results.</param>
/// <returns>
/// an enumerable of the newly connected NetworkInterface objects
/// </returns>
public IEnumerable<NetworkInterface> Connected(NetworkStatus lastStatus)
{
// enumerate the current list of interfaces:
foreach (var pair in _status)
{
// determine if the interface was in the last snapshot:
if (lastStatus._status.ContainsKey(pair.Key))
{
// if the current status is "Up" and the last
// status wasn't, the interface has connected.
if (lastStatus._status[pair.Key].OperationalStatus != OperationalStatus.Up &&
pair.Value.OperationalStatus == OperationalStatus.Up)
yield return pair.Value.Interface;
}
else
{
// if the interface was not in the last snapshot,
// and is "up" then it has connected.
if (pair.Value.OperationalStatus == OperationalStatus.Up)
yield return pair.Value.Interface;
}
}
}
The NetworkStatusMonitor
class runs a looping method (in its own thread so it doesn't block the rest of the application) that stores a new instance
of the NetworkStatus
class, waits a predefined number of milliseconds, then generates a new instance of the NetworkStatus
class,
and runs the comparison methods to identify any adapters that have connected, disconnected etc.
This is the monitor-task method:
/// <summary>
/// the task given to the monitor thread.
/// </summary>
private void MonitorTask()
{
// loop while the run flag is true.
while (_run)
{
try
{
// has the last status been taken?
if (_last == null)
{
// snapshot the current status.
_last = new NetworkStatus();
// sleep for the duration of the poll interval.
Thread.Sleep(_waitInterval);
// run to the next iteration.
continue;
}
else
{
// get the current network status:
NetworkStatus current = new NetworkStatus();
// test for changes and raise events where neccessary.
if (NetworkInterfaceConnected != null && _monitorNewConnections)
{
// evaluate all the network interfaces that have connected since the
// last snapshot
foreach (var ni in current.Connected(_last))
{
// test if the network interface was in the last snapshot:
OperationalStatus lastStatus = OperationalStatus.NotPresent;
if (_last.Contains(ni.Id))
lastStatus = _last[ni.Id].OperationalStatus;
// raise the interface connected event:
NetworkInterfaceConnected(this, new StatusMonitorEventArgs()
{
EventType = StatusMonitorEventType.Connected,
Interface = ni,
LastOperationalStatus = lastStatus
});
}
}
// test for interface dis-connections
if (NetworkInterfaceDisconnected != null && _monitorDisconnections)
{
// enumerate the network interfaces that were Up but are not now.
foreach (var ni in current.Disconnected(_last))
{
// raise the interface dis-connected event:
NetworkInterfaceDisconnected(this, new StatusMonitorEventArgs()
{
// set the event-type, interface and last status.
EventType = StatusMonitorEventType.Disconnected,
Interface = ni,
LastOperationalStatus = OperationalStatus.Up
});
}
}
// test for interface changes.
if (NetworkInterfaceChanged != null && _monitorAnyStatusChange)
{
// enumerate the interfaces that have changed status in any way since
// the last snapshot.
foreach (var ni in current.Changed(_last))
{
// find the last status of the interface:
OperationalStatus lastStatus = OperationalStatus.NotPresent;
if (_last.Contains(ni.Id))
lastStatus = _last[ni.Id].OperationalStatus;
// raise the interface changed event:
NetworkInterfaceChanged(this, new StatusMonitorEventArgs()
{
// set the event-type interface and last status.
EventType = StatusMonitorEventType.Changed,
Interface = ni,
LastOperationalStatus = lastStatus
});
}
}
// set last to the current.
_last = current;
// wait...
if (_run)
Thread.Sleep(_waitInterval);
}
// pulse any threads waiting in WaitForPoll.
lock (_pulse)
Monitor.PulseAll(_pulse);
}
catch (Exception exception)
{
// handle the exception....(real exception handler should go here)
Console.WriteLine(exception.ToString());
// increment the exception counter.
Interlocked.Increment(ref _exceptionCount);
}
}
}
The main method of the program class shows how this is put together and started up as a console application that writes messages each time a network interface connects or disconnects.
History
V1.0.