I'm trying to use await/async in order to make some synchronous code asynchronous. For example, this works and unblocks the UI thread:
private async void button1_Click(object sender, EventArgs e)
{
var task = DoRequestAsync();
textBox1.Text = "starting async task";
var text = await task;
textBox1.Text = text;
}
private async Task<string> DoRequestAsync()
{
try
{
var client = new HttpClient();
client.Timeout = new TimeSpan(0, 0, 0, 5);
await client.GetAsync("http://123.123.123.123"); // force a timeout exception
}
catch (Exception e)
{
}
return "done!";
}
But this doesn't, and will hang the UI thread:
private async void button1_Click(object sender, EventArgs e)
{
var task = DoRequestAsync();
textBox1.Text = "starting async task";
var text = await task;
textBox1.Text = text;
}
private async Task<string> DoRequestAsync()
{
try
{
var request = WebRequest.Create("http://123.123.123.123");
request.Timeout = 5000;
request.GetResponse(); // force a timeout exception
}
catch (Exception e)
{
}
return "done!";
}
I'm trying to understand why this is the case. I was under the impression that var task = DoRequestAsync()
will create a new thread and run everything in the method asynchronously, but that appears to not be the case.
I can use this to make it work:
await Task.Run(() => {
var request = WebRequest.Create("http://123.123.123.123");
request.Timeout = 5000;
request.GetResponse();
});
But this seems a bit hacky and I'm not sure if it's the right solution to this issue. Does anybody know how I can just run a bunch of synchronous code in an asynchronous way using Tasks and async/await?
That's the exactly right solution.
If you want to use async, you have to make sure you async all the way down. In other words, if you don't have async version of the calling method, you need to wrap it using Task by yourself.
That's the right solution.
WebRequest.GetResponse
is not an async method therefore it does not return a Task. It cannot run asynchronously.Actually, what you have there is the most correct and shorthand solution you can get (with
Task.Run
).It's not magic. In order for it to run asynchronously, a new Task (not thread) must be created in your async method or it must await on one or more methods)that return either
Task
,Task<T>
orvoid
(this is for event handlers).Your last statement in the method
return "done!";
just returns a completedTask<string>
with result "done".As a side note, this is why HttpClient is becoming the de facto class HTTP requests, especially for interoperating with web APIs but also for general purpose GETs/POSTs/etc: it has async support.
Tasks also have support to wrap Begin*/End* functions (conforming to the former asynchronous programming model - APM). You can also do: