1

I have this code to check if Server is available or not:

public static async Task<bool> PingServer()
{
    System.Net.NetworkInformation.Ping p1 = new System.Net.NetworkInformation.Ping();

    System.Net.NetworkInformation.PingReply PR = await p1.SendPingAsync("pc2");

    // check when the ping is not success
    if (PR.Status != System.Net.NetworkInformation.IPStatus.Success)
    {
        return false;
    }
    return true;
}

Now, my problem is that SendPingAsync does not support CancellationTokenSource so how can I cancel the last ping to perform a new one to prevent a lot of pings?

When the server is lost it takes seconds to PingServer() return a false value.

This is how I call PingServer():

var task = await PingServer();

if (task == true)
{
  //do some stuff like retrieve a table data from SQL server.
}

Why I use ping? because when I want to get a table from SQL server if the server is disconnected my app enter a breakpoint.

public  async  static Task<System.Data.Linq.Table<Equipment>> GetEquipmentTable()
{  
   try
    {
        DataClassesDataContext dc = new DataClassesDataContext();
        // note : i tried so many ways to get table synchronize but it still freeze my UI ! 
        return await Task.Run(() => dc.GetTable<Equipment>());               
    }
    catch
    {
        return null;
    }
}

EDIT : I used ping to reduce chance of entering my app in brake mode by getting a table from database. is there any other way to prevent break mode ? is it best way to ping server before calling dc.GetTable() ?

Break point

Mamad
  • 446
  • 5
  • 22
  • [SendAsyncCancel](https://learn.microsoft.com/en-us/dotnet/api/system.net.mail.smtpclient.sendasynccancel)? – JohnyL May 06 '18 at 12:34
  • 2
    You do ofcourse, realize that getting a successful ping result, does not guarantee your connection won't break later, when you enter the `if` statement? You would be better off with some kind of retry strategy, when the task fails – ironstone13 May 06 '18 at 12:49
  • On top what ironstone13 said, catch all taht just returns null is also a bad idea. You end up swallowing all kinds of exceptions. And this way in dealin with Exogenous Exceptions is also not that good. There are two articles on Exception handling and I think you would benefit from them a lot: http://blogs.msdn.com/b/ericlippert/archive/2008/09/10/vexing-exceptions.aspx | http://www.codeproject.com/Articles/9538/Exception-Handling-Best-Practices-in-NET – Christopher May 06 '18 at 13:05
  • Yes i do. I used ping to reduce chance of entering my app in brake mode by getting a table from database. is there any other way to prevent break mode ? is it best way to ping server before calling dc.GetTable() ? – Mamad May 06 '18 at 18:14

3 Answers3

3

Have you considered using the timeout parameter?

From the documentation:

This overload allows you to specify a time-out value for the operation.

If that doesn't suffice and your problem is that the ping call is blocking, you could perform it on a background thread providing this is tightly controlled.

jmdon
  • 997
  • 9
  • 17
  • 1
    thank you but that's not my problem, maybe in a situation i want call ping() so many times in a second so i want cancel other pings before new one ! then i can sure i have just one ping await !!! – Mamad May 06 '18 at 12:40
  • 1
    @Mamad, if you don't want to send a lot of pings on different threads in parallel, don't - schedule your pings as periodically running tasks, and each of those could have a timeout like just described in his answer – ironstone13 May 06 '18 at 12:45
2

Consider

public static async Task<bool> PingServer() {
    using (var ping = new System.Net.NetworkInformation.Ping()) {
        try {
            var maxDelay = TimeSpan.FromSeconds(2); //Adjust as needed
            var tokenSource = new CancellationTokenSource(maxDelay);
            System.Net.NetworkInformation.PingReply PR = await Task.Run(() => 
                ping.SendPingAsync("pc2"), tokenSource.Token);
            // check when the ping is not success
            if (PR.Status != System.Net.NetworkInformation.IPStatus.Success) {
                return false;
            }
            return true;
        } catch {
            return false;
        }
    }
}

Where the ping is done with a cancellation token using Task.Run; If the ping result returns before the allotted time then all is well.

wrapped the component in a using to dispose of it when exiting function.

Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • 4
    Could you please elaborate, if it really solves the problem `ping.SendPingAsync` is just wrapped in another task. And yes, you pass the `CancellationTokenSource` to that **other** task, but since `Ping` does not care about this `CancellationTokenSource` the network calls are not really cancelled, or are they? Or is this just a variation of the **timeout** theme? – ironstone13 May 06 '18 at 13:08
  • 1
    This is a good answer. You dont really care if the Ping is truly cancelled. All you really care about is that the caller is unblocked. The ping then becomes a fire and forget . The ping will eventually timeout and clean itself up, but you dont care about it. – Menace Mar 06 '23 at 12:35
  • I take back my last comment. In reading the docs for Task.Run the cancel token is only used if the task has not yet run. So it doesnt do what we want. Use TaskCompletionSource instead with something like: var tcs = new TaskCompletionSource(); cancelSource.Token.Register(() => tcs.TrySetCanceled(), false); await Task.WhenAny(Task.WhenAll(aTasks), tcs.Task); // wait for them all to finish (or be canceled) – Menace Mar 07 '23 at 15:38
1

The system you depend on might fail, or the connection can go down right after your ping, when you're executing your code.

This is why a retry strategy is a much more robust approach then simply pinging a system before calling it.

Here is how you can implement a retry Cleanest way to write retry logic?

I would go with a retry approach, but if you still want to stay with your design you could

  • Schedule a periodic task to ping the system in question Is there a Task based replacement for System.Threading.Timer?
  • Make sure you schedule this periodic task in one central place (application startup or the like)
  • Invoke your PingServer from this periodic task and make sure you call Ping.SendAsync with PingOptions.Timeout being set, see this overload
  • From your PingServer set some kind of shared state, it could be a static variable, or an implementation of the Registry pattern
  • Make sure your shared state is thread-safe
  • The rest of your code can call this shared state, to find out if a system is online and available

As you can see, this approach is more complex, but you will prevent "lots of pings" to the system you depend on

ironstone13
  • 3,325
  • 18
  • 24