Reputation: 1196
I have a lambda expression with an async call inside
public async Task UploadFile(string id)
{
Progress<double> progress = new Progress<double>(async x =>
{
await Clients.Client(id).SendAsync("FTPUploadProgress", x);
});
await client.DownloadFileAsync(localPath, remotePath, true, FluentFTP.FtpVerify.Retry, progress);
}
I want to call the async method when progress is changed.
I'm getting the following warning:
This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API call
How can I make this method asynchronous?
Should I rewrite the lambda with a System.Action<T>
class?
Upvotes: 0
Views: 4902
Reputation: 247088
Use an event handler and raise it in the progress action. the event handler will allow async calls.
Luckily Progress<T>
has a ProgressChanged
event that you can subscribe to.
Review the following example based on the presented code in original problem
public async Task UploadFile(string id) {
EventHandler<double> handler = null;
//creating the handler inline for compactness
handler = async (sender, value) => {
//send message to client asynchronously
await Clients.Client(id).SendAsync("FTPUploadProgress", value);
};
var progress = new Progress<double>();
progress.ProgressChanged += handler;//subscribe to ProgressChanged event
//use the progress as you normally would
await client.DownloadFileAsync(localPath, remotePath, true, FluentFTP.FtpVerify.Retry, progress);
//unsubscribe when done
progress.ProgressChanged -= handler;
}
So now when progress is reported, the event handler can make the asynchronous call.
Reference Async/Await - Best Practices in Asynchronous Programming
Another option would be to create you own IProgress<T>
implementation that takes a Func<Task<T>>
that would allow for async calls, but that might be overkill.
Upvotes: 4
Reputation: 1126
I think you missunderstood the usage of the Progress<T>
class. The Compiler complains, that your Method UploadFile
lacks an await
operator. Your lambda would execute asynchronous, when it would be called.
So heres a short Summary how to use the IProgressyT>
interface:
If you have a Method that should support reporting of Progress, it can take an IProgress<T>
as an Parameter and communicate its porgress through this object. It does not perform the monitored Operation. The Lambda you supply is executed each time the Report()
Method is called on the Progress<T>
. This Lambda usually is used to update the UI.
Here is an example for that.
public async Task DoStuff(IProgress<double> progress = null)
{
for(int i = 0; i < 100; ++i)
{
await Task.Delay(500);
progress?.Report((double)(i +1) / 100);
}
}
// somewhere else in your code
public void StartProgress(){
var progress = new Progress(p => Console.WriteLine($"Progress {p}"));
DoStuff(progress);
}
Upvotes: 2