Reputation: 67
I'm working on a legacy application which communicates against an external machine and the communication is made thru file. Basically machine A writes a file, B get it and reply with another file. Currently all works fine but I have a code which is called every 5 seconds that checks if the remote directory (where the files are written) exists or not. Tihs is the code:
private delegate bool DirectoryExistsDelegate(string folder);
public static bool DirectoryExists(string path, int timeout = 2000)
{
Func<bool> func = () => Directory.Exists(path);
Task<bool> task = new Task<bool>(func);
task.Start();
return task.Wait(timeout) && task.Result;
}
It seems that the method above freeze the UI, particularly when we're using a network share, such \\10.100.100.1\sharedFolder So I thought to ping the host before try to access:
private static IPStatus PingStatus;
public static async void PingIP(string IPaddress, int timeout = 2000)
{
// Verifica indirizzo IP
if (string.IsNullOrEmpty(IPaddress)) return;
Ping s = new Ping();
PingStatus = await s.SendPingAsync(IPaddress, timeout).ContinueWith(pingTask => pingTask.Result.Status);
}
private delegate bool DirectoryExistsDelegate(string folder);
public static bool DirectoryExists(string path, int timeout = 2000)
{
if (path.StartsWith("\\"))
{
string[] address = path.Split('\\');
PingIP(address[2], timeout);
if (PingStatus != IPStatus.Success) return false;
}
Func<bool> func = () => Directory.Exists(path);
Task<bool> task = new Task<bool>(func);
task.Start();
return task.Wait(timeout) && task.Result;
}
I call the main method as:
if (!Uti.DirectoryExists(PathCom.Value, 5000))
return false;
I dunno if the idea is correct or not, but is logically right I guess. The problem is that the PingStatus return always True (at first call), event the server does not exists, since the second seems work fine. How th let SendPingAsync await the ping result and not freeze the UI?
Upvotes: 0
Views: 1343
Reputation: 4177
So, there are a couple of things wrong with your code:
public static async void PingIP
should be
public static async Task PingIP
PingIP(address[2], timeout);
should be
await PingIP(address[2], timeout);
Calling synchronous code from a Task, does not make your code asynchronous. Synchronous code, wrapped in a Task, is still synchronous code. You can wrap the calls to synchronous code in Task.Run
, to utilize the threadpool, that makes it 'look' asynchronous from your UI thread point of view.
Func<bool> func = () => Directory.Exists(path);
Task<bool> task = new Task<bool>(func);
task.Start();
return task.Wait(timeout) && task.Result;
Should be
bool exists = await Task.Run(() => Directory.Exists(path));
Or to enforce a timeout:
var task = Task.Run(() => Directory.Exists(path));
if (await Task.WhenAny(task, Task.Delay(timeout)) == task) {
// task completed within timeout
} else {
// timeout logic
}
Seeing above code, you can see that you should make the function DirectoryExists
asynchronous as well. And the code that calls DirectoryExists
as well. etc. etc.
Never call .Result on Task (almost never). That will make your UI thread freeze again. That's how you do asynchronous programming. Async all the way.
Upvotes: 3