Introduction
In this article, I will present my custom class NetworkManager
and explain my design idea. And I will present other references, that is using the Win32 API InternetGetConnectedState
and the .NET Framework NetworkInterface
, but at last, I will not use InternetGetConnectedState
and NetworkInterface
.
In here, you will learn these techniques.
Background
I need to monitor the network status in my project. This is to check if the cable has a bad contact or not and to check if the network is enabled or not. So I developed a simple tool to test.
Why do I need to monitor the network status? Because in our product, we had an issue where the cable had a bad contact with the network vard. So the user requested for a solution and we talked about this issue in our team meeting. We thought we needed a complete solution, and maybe the user will also disable the network in the environment.
Using the Code
I use a singleton to manage all the network information. Now, call this code to initialize and monitor:
NetworkManager.Instance.StartMonitor();
And foreach NetworkManager.Instance.Informations.Values
to get the required information:
foreach(NetworkInfo info in NetworkManager.Instance.Informations.Values)
{
Console.WriteLine("Device Name:" + info.DeviceName);
Console.WriteLine("Adapter Type:" + info.AdapterType);
Console.WriteLine("MAC Address:" + info.MacAddress);
Console.WriteLine("Connection Name:" + info.ConnectionID);
Console.WriteLine("IP Address:" + info.IP);
Console.WriteLine("Connection Status:" + info.Status.ToString());
}
At last call this to destroy:
NetworkManager.Instance.Destory();
About the Code
public enum NetConnectionStatus
{
Disconnected = 0,
Connecting = 1,
Connected = 2,
Disconnecting = 3,
HardwareNotPresent = 4,
HardwareDisabled = 5,
HardwareMalfunction = 6,
MediaDisconnected = 7,
Authenticating = 8,
AuthenticationSucceeded = 9,
AuthenticationFailed = 10,
InvalidAddress = 11,
CredentialsRequired = 12
}
First, the enum named NetConnectionStatus
that is a reference from the property NetConnectionStatus
in the Win32NetworkAdapter
class.
In my project, I need the information, so I declared it.
static readonly NetworkManager m_instance = new NetworkManager();
I use singleton for NetworkManager
, because I think this class will get the information as network cards, and all instances will get the same information, so singleton is the best.
static NetworkManager()
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher(
"SELECT * FROM Win32_NetworkAdapter WHERE NetConnectionID IS NOT NULL");
foreach (ManagementObject mo in searcher.Get())
{
NetworkInfo info = new NetworkInfo();
info.DeviceName = ParseProperty(mo["Description"]);
info.AdapterType = ParseProperty(mo["AdapterType"]);
info.MacAddress = ParseProperty(mo["MACAddress"]);
info.ConnectionID = ParseProperty(mo["NetConnectionID"]);
info.Status = (NetConnectionStatus)Convert.ToInt32(mo["NetConnectionStatus"]);
SetIP(info);
m_Informations.Add(info.ConnectionID, info);
}
}
static void SetIP(NetworkInfo info)
{
ManagementClass objMC =
new ManagementClass("Win32_NetworkAdapterConfiguration");
foreach (ManagementObject mo in objMC.GetInstances())
{
try
{
if (!(bool)mo["ipEnabled"])
continue;
if (mo["MACAddress"].ToString().Equals(info.MacAddress))
{
string[] ip = (string[])mo["IPAddress"];
info.IP = ip[0];
string[] mask = (string[])mo["IPSubnet"];
info.Mask = mask[0];
string[] gateway = (string[])mo["DefaultIPGateway"];
info.DefaultGateway = gateway[0];
break;
}
}
catch (Exception ex)
{
Debug.WriteLine("[SetIP]:" + ex.Message);
}
}
}
The ConnectionID
will show in the Windows Console, so I use the property to be a key.
I use ManagementObjectSearcher
to get the network card information in Win32_NetworkAdapter
, but IP, subnet, and gateway is available in Win32_NetworkAdapterConfiguration
.
WQL can't use the join table, so I use the SetIP
function that will get the IP address in Win32_NetworkAdapterConfiguration
by MACAddress, because MACAddress exists in Win32_NetworkAdapter
and Win32_NetworkAdapterConfiguration
.
Executing Image
When we disable the network in the Console, the Monitor will get the disconnect status.
When the cable has a bad contact, it gets that information.
This is when the Connect succeeds:
Points of Interest
Apart from WMI, I also try InternetGetConnectedState
API and NetworkInterface
.
public class WinINET
{
[DllImport("wininet.dll", SetLastError = true)]
public extern static bool InternetGetConnectedState(out int lpdwFlags,
int dwReserved);
[Flags]
public enum ConnectionStates
{
Modem = 0x1,
LAN = 0x2,
Proxy = 0x4,
RasInstalled = 0x10,
Offline = 0x20,
Configured = 0x40,
}
}
static void WinINETAPI()
{
int flags;
bool isConnected = WinINET.InternetGetConnectedState(out flags, 0);
Console.WriteLine(string.Format("Is connected :{0} Flags:{1}", isConnected,
((WinINET.ConnectionStates)flags).ToString()));
}
When I try the InternetGetConnectedState
API, I find the API already returns true when I disable a network card. (I have two network cards.)
In my project, the front-end will get the client's data with LAN but the front end also needs to connect to the WAN with another network card. So I think this function will not help me handle all the network status. If you want to use an API in .NET, you must use DllImport
to declare the API.
The enum ConnectionStates
is a flag value, converts flags to ConnectionStates
, and using ToString()
, we can get the required information.
For example, when flags = 0x18, convert to ConnectionStates
and using ToString()
will get the "LAN,RasInstalled" string.
static void NetInfo()
{
foreach (NetworkInterface face in
NetworkInterface.GetAllNetworkInterfaces())
{
Console.WriteLine("=================================================");
Console.WriteLine(face.Id);
Console.WriteLine(face.Name);
Console.WriteLine(face.NetworkInterfaceType.ToString());
Console.WriteLine(face.OperationalStatus.ToString());
Console.WriteLine(face.Speed);
}
}
Here are the two network cards in my PC.
When I use this code to get network information and the network is connected, it will display the information. The OperationalStatus
property will show up. And it will get Down when I remove the cable from the network card.
But I think the perfect solution not just handles the network cable, so I tried to disable the network in the Windows Console. After disabling the network, I run the code again, but it doesn't show the disabled network card's information.
So I think NetworkInterface
may not be a perfect solution.
History
- V1.3: Updated information and background.
- V1.2: Updated source code project.
- V1.1: Added more detail.
- V1.0: Added code for Network Monitor.