How to create HttpWebRequest without interrupting async/await?
.net-4.5, async-await, c#, httpwebrequest
Solution
Interestingly, I'm not seeing a blocking delay with `WebRequest.Create` or `HttpClient.PostAsync`. It might be something to do with DNS resolution or proxy configuration, although I'd expect these operations to be implemented internally as asynchronous, too.
Anyway, as a workaround you can start the request on a pool thread, although this is not something I'd normally do:
private async Task<List<string>> DownloadSomething()
{
var request = await Task.Run(() => {
// WebRequest.Create freezes??
return System.Net.WebRequest.Create("https://valid.url");
});
// ...
using (var ss = await request.GetRequestStreamAsync())
{
await ss.WriteAsync(...);
}
using (var rr = await request.GetResponseAsync())
using (var ss = rr.GetResponseStream())
{
//read stream and return data
}
}
That would keep the UI responsive, but it might be difficult to cancel it if user wants to stop the operation. That's because you need to already have a `WebRequest` instance to be able to call `Abort` on it.
Using `HttpClient`, cancellation would be possible, something like this:
private async Task<List<string>> DownloadSomething(CancellationToken token)
{
var httpClient = new HttpClient();
var response = await Task.Run(async () => {
return await httpClient.PostAsync("https://valid.url", token);
}, token);
// ...
}
With `HttpClient`, you can also register a `httpClient.CancelPendingRequests()` callback on the cancellation token, like this.
[UPDATE] Based on the comments: in your original case (before introducing `Task.Run`) you probably did not need the `IProgress<I>` pattern. As long as `DownloadSomething()` was called on the UI thread, every execution step after each `await` inside `DownloadSomething` would be resumed on the same UI thread, so you could just update the UI directly in between `awaits`.
Now, to run the whole `DownloadSomething()` via `Task.Run` on a pool thread, you would have to pass an instance of `IProgress<I>` into it, e.g.:
private async Task<List<string>> DownloadSomething(
string url,
IProgress<int> progress,
CancellationToken token)
{
var request = System.Net.WebRequest.Create(url);
// ...
using (var ss = await request.GetRequestStreamAsync())
{
await ss.WriteAsync(...);
}
using (var rr = await request.GetResponseAsync())
using (var ss = rr.GetResponseStream())
{
// read stream and return data
progress.Report(...); // report progress
}
}
// ...
// Calling DownloadSomething from the UI thread via Task.Run:
var progressIndicator = new Progress<int>(ReportProgress);
var cts = new CancellationTokenSource(30000); // cancel in 30s (optional)
var url = "https://valid.url";
var result = await Task.Run(() =>
DownloadSomething(url, progressIndicator, cts.Token), cts.Token);
// the "result" type is deduced to "List<string>" by the compiler
Note, because `DownloadSomething` is an `async` method itself, it is now run as a nested task, which `Task.Run` transparently unwraps for you. More on this: Task.Run vs Task.Factory.StartNew.
Also check out: Enabling Progress and Cancellation in Async APIs.
Problem
I have a bunch of slow functions that are essentially this: ``` private async Task<List<string>> DownloadSomething() { var request = System.Net.WebRequest.Create("https://valid.url"); ... using (var ss = await request.GetRequestStreamAsync()) { await ss.WriteAsync(...); } using (var rr = await request.GetResponseAsync()) using (var ss = rr.GetResponseStream()) { //read stream and return data } } ``` This works nicely and asynchronously except for the call to `WebRequest.Create` - this single line freezes the UI thread for several seconds which sort of ruins the purpose of async/await. I already have this code written using `BackgroundWorker`s, which works perfectly and never freezes the UI. Still, what is the correct, idiomatic way to create a web request with respect to async/await? Or maybe there is another class that should be used? I've seen this nice answer about asyncifying a `WebRequest`, but even there the object itself is created synchronously.