0
votes

I was reading the following topic http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

and decided to write a common utility method in my library to do a GET on remote url via HTTPClient

public static async Task<T> GetAsync<T>(HttpGetObject getObject)
{
    string baseUrl = getObject.BaseUrl;
    string actionUrl = getObject.ActionRelativeUrl;
    string acceptType = getObject.AcceptType;

    using (var client = new HttpClient())
    {
        client.BaseAddress = new Uri(baseUrl);
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(acceptType));

        AddCustomHeadersToHttpClient(client, getObject);

        // HTTP GET
        HttpResponseMessage httpResponseMessage = await client.GetAsync(actionUrl).ConfigureAwait(false);
        if (httpResponseMessage.IsSuccessStatusCode)
        {
            T response = await httpResponseMessage.Content.ReadAsAsync<T>().ConfigureAwait(false);
            return response;
        }
        else
        {
            string message = httpResponseMessage.Content.ReadAsStringAsync().Result;
            throw new Exception(message);
        }
    }
    return default(T);
}

I know the "await httpResponseMessage.Content.ReadAsAsync().ConfigureAwait(false)" will prevent the deadlock in the above code First: My query is for "string message = httpResponseMessage.Content.ReadAsStringAsync().Result" line, will .Result can cause deadlock or not in that line?

Second: If I call that code from UI like this:

public static object DoGet()
{
    // Build getObject
    var task = Utility.GetAsync(getObject);
    task.Wait();
    var response = task.Result;
    return response;
}

Will that cause a deadlock?

Please note that I know to avoid all the mess with async-await, all the methods from UI to DAL must be async-await but I am not in position at this moment to change all that structure, my goal at this moment is to call HttpClient library and do a few GET operations.

So my questions is that will the above code can cause a deadlock?

Third:

Is task.Wait(); even needed in the above code?

1
So you were reading article "Don't block on async code", then you wrote a method that blocks on async code. What is the question actually?Evk
I added the last paragraph for that explanation. It is not possible for me to change the signature of all the methods to make it complete async-awaitRaghav
@Raghav if you can't change the code to be async: don't try to change it to be async. What you are discussing is "sync over async", which is an anti-pattern and actively dangerous. If you need to expose sync: use a sync API throughout, or be prepared to spend a lot of time getting familiar with async details to the extent where you can anticipate what will happen when you call .Result / .Wait()Marc Gravell
@MarcGravell Thanks for your valuable advice on this line "If you need to expose sync: use a sync API throughout,". That means, I can't use HttpClient, Right? I noticed that HttpClient is exposing GetAsync only and there is no Get method there. Which other client will you suggest to make a call to remote URL to get the response?Raghav

1 Answers

6
votes

In the general case, you should assume that yes, calling .Result or .Wait() on anything awaitable is dangerous and can deadlock (unless you are the library issuing the task, and you understand the full context). It is possible that it will work OK in some specific cases, but you should not rely on that behaviour, even if it works today.