我正试图了解async/await
并编写以下控制台应用程序以下载给定网址的网页内容(基于来自dotnetperls的httpclient example)
没有任何内容写入文件。我在这里做错了什么?
static void Main()
{
AsyncExample();
}
static async void AsyncExample()
{
Task<string> task = DownloadPageAsync();
string result = await task;
WriteToFile(result, someFileName);
}
static async Task<string> DownloadPageAsync()
{
string page = "http://en.wikipedia.org/wiki/Asynchronous_I/O";
string result = string.Empty;
using(HttpClient client = new HttpClient())
using(HttpResponseMessage response = await client.GetAsync(page))
using(HttpContent content = response.Content)
{
result = await content.ReadAsStringAsync();
}
return result;
}
答案 0 :(得分:9)
这是因为申请被终止了。您需要等到AsyncExample完成后才让主要完成它的代码。
目前,Main方法在您的任务完成之前完成,因此无论任务状态如何,应用程序都会立即终止。
要解决此问题,您需要等到AsyncExample完成。
一种方法是使用Task.Wait()方法使用continuation然后等待这个 continuation 任务。
我们使用延续来处理错误。从原始任务中读取Result属性将在出错时抛出异常(如果您希望在此处抛出异常,请执行此操作)。
但是,如果我们没有使用延续,并且我们没有从错误的任务中读取Exception值或Result,那么在完成Task时,应用程序可以终止。继续处理这两种情况的技巧。
static async Task AsyncExample()
{
Task<string> task = DownloadPageAsync();
string result = await task;
WriteToFile(result, someFileName);
}
public static void Main(string[] args)
{
var task = AsyncExample();
task.Wait();
// task.ContinueWith( t => { }).Wait();
}
答案 1 :(得分:3)
对m1o2的答案发表评论的时间太长了一些:
但是,如果我们没有使用延续,并且我们没有从错误的任务中读取Exception值或Result,那么在完成Task时,应用程序可以终止。
未处理的异常在TPL中的行为方式发生了重大变化。在.NET 4.0中,UnobservedTaskException
将终止您的进程。在.NET 4.5中,不会。有关详细信息,请参阅Stephan Toub的this blog post
无需延续。使用await task
时,编译器将我们的代码提升到一个状态机,稍后将await
关键字后面的任何代码作为“延续”运行。如果在等待任务中发生异常,则一旦任务完成执行,它将被抛出。
访问Task.Wait
会传播AggregationException
,您无需访问Task.Result
或Task.Exception
。取from MSDN
:
在任务中运行的用户代码抛出的未处理异常将传播回加入线程,但本主题后面描述的某些方案除外。当您使用静态或实例
Task.Wait
或Task<TResult>.Wait
方法之一时,会传播异常,并通过将调用包含在try-catch语句中来处理它们。