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 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
).
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.
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>
or void
(this is for event handlers).
Your last statement in the method return "done!";
just returns a completed Task<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:
try
{
var request = WebRequest.Create("http://123.123.123.123");
request.Timeout = 5000;
await Task.Factory.FromAsync(request.BeginGetResponse(), request.EndGetResponse, null); // force a timeout exception
}
catch (Exception e)
{
//TODO handle exception here
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With