1

I'm pulling data from Amazon via HTTP. The code works just fine in a small demo project, but in my main app it doesn't. When I call FetchItem() I receive this output:

'System.Net.Http.Formatting.dll'. Cannot find or open the PDB file.

After await client.GetAsync() the function returns and url.Wait() waits forever.

Usage

Task<string> url = FetchItem("ItemName", requestUrl);
url.Wait();
return url.Result;

Source of FetchItem

private static async Task<string> FetchItem(string sItemName, string url)
{
    try
    {
        HttpClient client = new HttpClient();
        HttpResponseMessage response = await client.GetAsync(url);
        response.EnsureSuccessStatusCode();
        XElement content = await response.Content.ReadAsAsync<XElement>();
        XNamespace ns = NAMESPACE;
        var isValidResults = content.Descendants(ns + "IsValid").AsParallel();

        foreach (var item in isValidResults)
        {
            if (item.Value != "True")
                return "Invalid Request";
        }
        var titleResults = content.Descendants(ns + sItemName).AsParallel();
        foreach (var item in titleResults)
        {
            if (item.Name == ns + sItemName)
                return item.Value; 
            // depending on the keyword, results can be quite fun.... :-)
        }
    }
    catch (Exception e)
    {
        System.Console.WriteLine("Caught Exception: " + e.Message);
        System.Console.WriteLine("Stack Trace: " + e.StackTrace);
    }
    return "Error";
}
JasonMArcher
  • 14,195
  • 22
  • 56
  • 52
user3305711
  • 441
  • 5
  • 16
  • Have closed as duplicate because all you are asking is: How to apply a timeout to a task? – usr Jun 08 '14 at 12:03
  • You have edited the question so that now it is entirely different and no longer duplicate. I'll reopen. – usr Jun 08 '14 at 22:27
  • 1
    Actually the problem isn't really related to `HttpClient`, but rather to how async methods work... – Thomas Levesque Jun 08 '14 at 22:50

2 Answers2

3

I assume you're calling this code on the UI thread. What's happening is that Waiting for the task to complete causes a deadlock. Your FetchItem method is asynchronous, and when you use await in it, the code that follows is transformed to a callback (called the continuation) that will be executed on the UI thread. But since the UI thread is busy waiting for the task to complete, it can't process the callback, so the task never completes. Hence the deadlock.

You should never Wait on the result of an async method. If you call an async method, use await to get its result. It means that the calling method also has to be async. Basically, when you start to use async in some part of the code, all the code that uses it needs to become async as well... (*)


(*) well, that's not exactly true. You can prevent the async method from resuming on the UI thread, by calling ConfigureAwait(false) on the method you await. If you do that, the continuation will run on a thread pool thread, instead of the UI thread. This will also avoid the deadlock.

Thomas Levesque
  • 286,951
  • 70
  • 623
  • 758
  • Yes, the original demo is a consol app and I added the `Wait()` in my Forms app. The consol app works fine. So a consol app is async and a forms app not? The better question may be: What is the best way to use async methods like `FetchItem()` in a Forms app? – user3305711 Jun 09 '14 at 11:09
  • 1
    @user3305711, it works in a console app, because console apps don't have a UI context, so continuations are always posted to the thread pool. As I said in my answer, the best way is to do async all the way; if an event handler calls async code, make it async as well. – Thomas Levesque Jun 09 '14 at 12:03
0

I changed FetchItem() to run sync. That did it for me:

private static string GetItem(string sItemName, string url)
{
    try
    {
        HttpClient client = new HttpClient();
        HttpResponseMessage response = client.GetAsync(url).Result;
        response.EnsureSuccessStatusCode();
        XElement content = response.Content.ReadAsAsync<XElement>().Result;
        ...

It doesn't make sense to me to rewrite half my app to go async.

user3305711
  • 441
  • 5
  • 16