gafs
gafs

Reputation: 73

Why is delaying the task not executing it fully or blocking the UI?

private async Task<string> httpClient(CancellationToken cancelToken)
{
    HttpClient hc = new HttpClient();

    hc.Timeout = new TimeSpan(0, 0, 10);

    //Task.Delay(5000).Wait(); using this one, it blocks the UI thread
    //await Task.Delay(5000); using this one, it doesn't execute the task after delay

    if (cancelToken.IsCancellationRequested)
    {
        return null;
    }

    HttpResponseMessage response = await hc.GetAsync(new Uri("http://google.com/"));

    response.EnsureSuccessStatusCode();

    string responseData = await response.Content.ReadAsStringAsync();

    return responseData;
}

This is my async task and I have an issue trying to use delay inside of it. I have tried two methods and both seem to cause an issue with the task. Tried researching but couldn't find a way to fix my issue. Any help is appreciated

Other part of the code:

private async void Test()
{
    string response = await httpClient(token);
    Console.WriteLine("response: " + response);
}

private void button1_Click(object sender, EventArgs e)
{
    Task t = new Task(Test);
    t.Start();
    Console.WriteLine("task started");
    t.Wait();
    Console.WriteLine("task finished");
}

Upvotes: 2

Views: 77

Answers (1)

Marc Gravell
Marc Gravell

Reputation: 1064204

The problem is here:

private async void Test()
{
    string response = await httpClient(token);
    Console.WriteLine("response: " + response);
}

As soon as you've made something async void you've completely removed any ability to track status. Your new Task(Test); is using new Task(Action), which will report completion as soon as the code first returns to the caller - i.e. at the first non-complete await (in your case: the Task.Delay). To do what you want, you should really be using the Task.Run(Func<Task>) API (or avoiding Task.Run / Task.Start completely, relying on the async plumbing itself), with a private async Task Test() method.

Your event handler could then be:

private async void button1_Click(object sender, EventArgs e)
{
    Console.WriteLine("about to start task");
    var t = Task.Run(Test);
    Console.WriteLine("task started");
    await t;
    Console.WriteLine("task finished");
}

or to avoid the extra thread (as noted by Nkosi):

private async void button1_Click(object sender, EventArgs e)
{
    Console.WriteLine("about to start task");
    var t = Test();
    Console.WriteLine("task started");
    await t;
    Console.WriteLine("task finished");
}

Upvotes: 3

Related Questions