Deadlock on .Result from Web UI

2020-05-05 17:17发布

问题:

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:

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.