views:

429

answers:

7

Hi, I know that I am not the first to ask the question: How do I find out if my application is online or not? I found this post: StackOverflow. I want to do it with C# and .NET 3.5.

The recommendation is to ping the resource regularly. I am not very happy with that advice. I would rather detect a network change and THEN ping my service to check if it is online.

.NET provides two events for this purpose: NetworkChange.NetworkAvailabilityChanged NetworkChange.NetworkAddressChanged

The first event sounds good but it is fired only if the last network card which is online goes offline. I have several virtual network cards which have been installed by VMWare and those are always online. The second event works but between plugging the network cable and the event, there are often 5 seconds wait time. The Windows tray icon reacts more or less immediately when I am unplugging the cable. What is the best way to be as fast as this tray icon?

My workaround would be to poll NetworkInterface.GetAllNetworkInterfaces() every 500ms and to throw my own event in case that the status of a network adapter changed.

There must be a better solution :)

A: 

Pinging your resource regularly is the only option that will give you a notification if the service goes offline, as well as if the client goes offline. Potentially you want to handle both situations.

Tim
Yes, I know. For me, the risk that the network of a specific user is unavailable is much higher than the risk that the server is unavailable. We will ping, but not regularly but only when the application starts and when a network change occurs. Perhaps we will ping regularly but then not every 500ms :)
Kay
A: 

The windows tray icon is very likely connected to the network card drivers, i.e. below the operating system level which is why it can react so fast.

Since the network card is only one of many links between your client and the service that it accesses on the Internet, the only reliable way to detect whether or not the Internet is available is to poll some service out on the Internet, much the same way that ping does. In TCP/IP networking, this is known as a keepalive, and many protocols will have this built into them as an option.

Michael Dillon
A: 

About the pinging: depending on how you wish to interpret the results, pinging doesn't seem watertight to me. What if the target times out once in a while, while the connection remains alive? I have yet to see the server that never fails to respond to a ping.

Checking every X millis if the network interface is still online (NetworkInterface.OperationalStatus property) seems more reliable if you'd ask me.

EDIT: This article deals with network address events on a lower level than the System.Net.NetworkInformation.NetworkChange class, or so it seems. On my pc it works very fast, so hopefully you'll be able to use that solution.

Webleeuw
Thanks for the link. I had a look at it. It seems that NetworkChange is used. This is useful but I am not happy with it since it is too slow.
Kay
"I have yet to see the server that never fails to respond to a ping" - That's a bad assumption. Many networks drop ICMP packets.
0A0D
@Roboto: I don't understand your comment, perhaps due to a small communication discrepancy :). With that sentence I meant to point out the fact that ping is not reliable because a server could drop one or more ping packets even if it's online.More clearly: I have yet to see the server that always and ever responds to every ping it is send.
Webleeuw
A: 

Try this using NetworkChange class

using System.Net.NetworkInformation

private void Form5_Load(object sender, EventArgs e)
{
    NetworkChange.NetworkAvailabilityChanged += new NetworkAvailabilityChangedEventHandler(NetworkChange_NetworkAvailabilityChanged);
}

private void NetworkChange_NetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
{
    if (e.IsAvailable)
    {
        MessageBox.Show("Available");
    }
    else
    {
        MessageBox.Show("Not available");
    }
}
Anuraj
This works only for one network. If you have several networks, the event will only be fired when all networks are offline. This is not helpful in my case (see my description)
Kay
OOPs I missed that :(
Anuraj
A: 

You can use ping, but I would also build a simple call to return a "yes" if it is online. That way you do know if the server is up and that it is running your code. Also I would only call or ping when a network resource is needed and not continually.

Tony Borf
A: 

Doing a ping is definitely not the cleanest option, especially if it is a web server. Some hosts will disable response to ICMP traffic, so you may ping but not get a response. How about just handling the exception gracefully when it occurs?

baldy
Well, actually I am not sending a "ping" command. Instead I am calling a webservice on my webserver. This tells me if my WCF-Services are still alive :)
Kay
+2  A: 

I tried the link the Webleeuw suggested, but that code also needs between 4 and 10 seconds to notify me when I plug or unplug my cable. Now, I wanted to know if it just my computer or installation and I wrote my own Observer class which is based on NetworkInterface.GetAllNetworkInterfaces().

And: It works with lightning speed. My app reacts now as quickly as does the tray. The code is far from production code, it is just a quick hack. But this is what I will build upon now :)

using System;
using System.Net.NetworkInformation;
using Timer=System.Threading.Timer;

namespace NetworkCheckApp
{
public class NetworkStatusObserver
{
    public event EventHandler<EventArgs> NetworkChanged;

    private NetworkInterface[] oldInterfaces;
    private Timer timer;

    public void Start()
    {
        timer = new Timer(UpdateNetworkStatus, null, new TimeSpan(0, 0, 0, 0, 500), new TimeSpan(0, 0, 0, 0, 500));

        oldInterfaces = NetworkInterface.GetAllNetworkInterfaces();
    }

    private void UpdateNetworkStatus(object o)
    {
        var newInterfaces = NetworkInterface.GetAllNetworkInterfaces();
        bool hasChanges = false;
        if (newInterfaces.Length != oldInterfaces.Length)
        {
            hasChanges = true;
        }
        if (!hasChanges)
        {
            for (int i = 0; i < oldInterfaces.Length; i++)
            {
                if (oldInterfaces[i].Name != newInterfaces[i].Name || oldInterfaces[i].OperationalStatus != newInterfaces[i].OperationalStatus)
                {
                    hasChanges = true;
                    break;
                }
            }
        }

        oldInterfaces = newInterfaces;

        if (hasChanges)
        {
            RaiseNetworkChanged();
        }
    }

    private void RaiseNetworkChanged()
    {
        if (NetworkChanged != null)
        {
            NetworkChanged.Invoke(this, null);
        }
    }
}
}
Kay
A pity my edit didn't turn out to help you, but nice solution you provided yourself with :). I might use it myself in the (near) future, so thanks for providing it here.
Webleeuw