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.

Original source

Related problems