await WebClient.DownloadStringTaskAsync 永远等待,但访问 Result 属性 有效

await WebClient.DownloadStringTaskAsync waits forever but accessing Result property works

以下代码段工作正常(在控制台上打印标记):

System.Net.WebClient wc = new System.Net.WebClient();
var task1 = wc.DownloadStringTaskAsync("https://www.google.com.au");
Console.WriteLine(task1.Result); // works

但是当我等待任务时它只是永远等待并且任务的状态是 WaitingForActivation:

System.Net.WebClient wc = new System.Net.WebClient();
var task1 = wc.DownloadStringTaskAsync("https://www.google.com.au");
Console.WriteLine(await task1);
Console.WriteLine("done!"); // this never gets printed

我错过了什么?

编辑:完整代码:

static void Main(string[] args)
{
    DoIt(); 
}

static async void DoIt()
{
    System.Net.WebClient wc = new System.Net.WebClient();
    var task1 = wc.DownloadStringTaskAsync("https://www.google.com.au");
    Console.WriteLine(await task1);
    Console.WriteLine("done!"); // this never gets printed
}

What am I missing?

目前,根据您调用代码的方式,我看不出任务是怎样的 WaitingForActivation。一旦 DoIt 命中第一个 await,它就会将控制权交还给调用者,这是您的 Main 方法,它应该终止并关闭您的控制台。

使用 Task.Result 之所以有效,是因为它会同步阻塞异步方法,因此它会等待它完成,然后您会看到结果打印到控制台。

你真正需要做的是用 DoIt async Task 代替 async void,并在那里使用 Task.Wait 同步阻塞,所以 Main 不会' t 终止:

static void Main(string[] args)
{
    DoItAsync().Wait(); 
}

static async Task DoItAsync()
{
    System.Net.WebClient wc = new System.Net.WebClient();
    var task1 = wc.DownloadStringTaskAsync("https://www.google.com.au");
    Console.WriteLine(await task1);
    Console.WriteLine("done!"); // this never gets printed
}

注意使用 Task.ResultTask.Wait 只是为了让控制台不终止。在任何其他环境中(基于 UI 或 ASP.NET),您永远不应阻塞异步代码,而应始终 await 异步方法。

您没有 await-ing 或 Wait()-ing 您的 DoIt() 方法,即 async。由于无法使 Main() 变为 async,您唯一的选择是同步等待任务完成。

此外,awaitWait() 异步方法 returns void 是不可能的,因此我们必须使其成为 return Task(或 Task<T>,如果方法必须 return 某个值)。 returns void 异步方法的调用者无法知道它何时 returns 以及它是否抛出任何异常。

using System;
using System.Threading.Tasks;

public class Program
{
    public static void Main()
    {
        Program.DoIt().Wait();
    }

    private static async Task DoIt()
    {
        System.Net.WebClient wc = new System.Net.WebClient();
        var task1 = wc.DownloadStringTaskAsync("https://www.google.com.au");
        Console.WriteLine(await task1);
        Console.WriteLine("done!"); 
    }
}