通知正在进行的长时间运行的异步任务 - 正确的方式

Bar*_*osz 0 c# asynchronous progress async-await

我有一个控制台程序,它向外部 Web API 发送异步 HTTP 请求。( HttpClient.GetAsync());)
这些任务可能需要几分钟才能完成——在此期间,我希望能够向用户显示应用程序仍在运行——例如Console.WriteLine("I ain't dead - yet")每 10 秒发送一次。

我不知道如何正确地做到这一点,而不会有隐藏异常、引入死锁等的风险。

我知道 IProgress<T>,但是我不知道我是否可以在这种情况下引入它。我正在等待一个不报告进度的异步调用。(它本质上是一个调用 httpClient GetAsync() 方法的 SDK

另外:我无法将 GUI 设置为“InProgress”,因为没有 GUI,它是一个控制台应用程序 - 如果我不时不时地发送更新消息,它在用户看来似乎停止工作。

目前的想法:

            try
            {
                var task = httpClient.GetAsync(uri); //actually this is an SDK method call (which I cannot control and which does not report progress itself)

                while (!task.IsCompleted)
                {
                    await Task.Delay(1000 * 10);
                    this.Logger.Log(Verbosity.Verbose, "Waiting for reply...");
                }
                onSuccessCallback(task.Result);
            }
            catch (Exception ex)
            {
                if (onErrorCallback == null)
                {
                    throw this.Logger.Error(this.GetProperException(ex, caller));
                }
                this.Logger.Log(Verbosity.Error, $"An error when executing command [{action?.Command}] on {typeof(T).Name}", ex);
                onErrorCallback(this.GetProperException(ex, caller));
            }
Run Code Online (Sandbox Code Playgroud)

Aro*_*ron 5

让我为你整理一下这段代码

async Task Main()
{
    var reporter = new ConsoleProgress();
    var result = await WeatherWaxProgressWrapper(() => GetAsync("foo"), reporter);

    Console.WriteLine(result);
}



public async Task<int> GetAsync(string uri)
{
    await Task.Delay(TimeSpan.FromSeconds(10));
    return 1;
}

public async Task<T> WeatherWaxProgressWrapper<T>(Func<Task<T>> method, System.IProgress<string> progress)
{
    var task = method();
    while(!task.IsCompleted && !task.IsCanceled && !task.IsFaulted)
    {
        await Task.WhenAny(task, Task.Delay(1000));
        progress.Report("I ain't dead");
    }
    return await task;
}

public class ConsoleProgress : System.IProgress<string>
{
    public void Report(string value)
    {
        Console.WriteLine(value);
    }
}
Run Code Online (Sandbox Code Playgroud)