110

I created Windows Phone 8.1 project and I am trying to run async method GetResponse<T>(string url) on button click and waiting for the method to finish, but method is never finishing. Here is my code:

private void Button_Click(object sender, RoutedEventArgs 
{
      Task<List<MyObject>> task = GetResponse<MyObject>("my url");
      task.Wait();
      var items = task.Result; //break point here
}

public static async Task<List<T>> GetResponse<T>(string url)
{
    List<T> items = null;
    HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);

    var response = (HttpWebResponse)await Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null);
    try
    {
        Stream stream = response.GetResponseStream();
        StreamReader strReader = new StreamReader(stream);
        string text = strReader.ReadToEnd();
        items = JsonConvert.DeserializeObject<List<T>>(text);
    }
    catch (WebException)
    {
        throw;
    }
    return items;
}

It will hang on task.Wait().

I changed my button click method to async and used await before the async method and I get the result(await GetResponse<string>("url")). What is wrong with Task<List<string>> task = GetResponse<string>("url")? What am I doing wrong?

Thanks for the help!

2
  • 12
    Just a small note, it is a general convention that async methods are suffixed with Async, i.e. your method name would be GetResponseAsync. Commented Feb 19, 2015 at 8:46
  • Calling task.Wait(); is redundant here. task.Result will already call task.Wait() when necessary. Commented Mar 5, 2021 at 19:16

4 Answers 4

177

You're the victim of the classic deadlock. task.Wait() or task.Result is a blocking call in UI thread which causes the deadlock.

Don't block in the UI thread. Never do it. Just await it.

private async void Button_Click(object sender, RoutedEventArgs 
{
      var task = GetResponseAsync<MyObject>("my url");
      var items = await task;
}

Btw, why are you catching the WebException and throwing it back? It would be better if you simply don't catch it. Both are same.

Also I can see you're mixing the asynchronous code with synchronous code inside the GetResponse method. StreamReader.ReadToEnd is a blocking call --you should be using StreamReader.ReadToEndAsync.

Also use "Async" suffix to methods which returns a Task or asynchronous to follow the TAP("Task based Asynchronous Pattern") convention as Jon says.

Your method should look something like the following when you've addressed all the above concerns.

public static async Task<List<T>> GetResponseAsync<T>(string url)
{
    HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
    var response = (HttpWebResponse)await Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null);

    Stream stream = response.GetResponseStream();
    StreamReader strReader = new StreamReader(stream);
    string text = await strReader.ReadToEndAsync();

    return JsonConvert.DeserializeObject<List<T>>(text);
}
Sign up to request clarification or add additional context in comments.

3 Comments

I also often catch an exception and then throw it. This allows me to add a breakpoint when debugging.
@GaryH please don't do that :) just set VS to break on exceptions, don't pollute your code with superfluous error handling, that is what the tools are for
That's your opinion of course. Some exceptions are expected so I don't want to break on those. Break on all would not be acceptable. There are places where I want to have it stop to examine context before it gets passed up to a handler and the context get's lost. Especially true in situations where the issue is intermittent and not easily duplicated.
37

This is what's killing you:

task.Wait();

That's blocking the UI thread until the task has completed - but the task is an async method which is going to try to get back to the UI thread after it "pauses" and awaits an async result. It can't do that, because you're blocking the UI thread...

There's nothing in your code which really looks like it needs to be on the UI thread anyway, but assuming you really do want it there, you should use:

private async void Button_Click(object sender, RoutedEventArgs 
{
    Task<List<MyObject>> task = GetResponse<MyObject>("my url");
    var items = await task;
    // Presumably use items here
}

Or just:

private async void Button_Click(object sender, RoutedEventArgs 
{
    var items = await GetResponse<MyObject>("my url");
    // Presumably use items here
}

Now instead of blocking until the task has completed, the Button_Click method will return after scheduling a continuation to fire when the task has completed. (That's how async/await works, basically.)

Note that I would also rename GetResponse to GetResponseAsync for clarity.

2 Comments

I've added async to my button click event handler and am awaiting the async task but the async task is still running on my main thread and blocking the Windows Form UI. Any ideas why when I'm following the above example? Thanks
@ChrisWalsh: Yes, the async task would still run on your main thread. If it's truly asynchronous (e.g. doing asynchronous IO) that should be fine. It's not fine if that task performs blocking operations. I suggest you ask a new question with a complete example.
0

@ChrisWalsh: If you use Task.Run() and call the async task inside that function, the task will run on a new UI thread and prevent blocking your UI.

Comments

-5

use below code

 Task.WaitAll(Task.Run(async () => await GetResponse<MyObject>("my url")));

3 Comments

Task.WaitAll will block in the same way as task.Wait.
question was "button click and waiting for the method to finish" so above code snip will wait until method to finish.
This is EXACTLY what I needed.. THank you. I have a user clicking a button.. that button does different things... one of which MAY end up needing to call an Asyc Process. Needed to know how to halt.. allow that process to finish, so my current thread can continue on to the next step. Works perfect!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.