问题描述:

I've found a lot on this topic but none of the examples/answers seem to address our issue. We keep getting warnings saying the method below (and others like it) lack await, but when we try to add await we get "can't await this" (wherever we try to add the await). What are we doing wrong?

protected async Task<T> PerformGet<T>(string requestUri, bool appendHeader)

{

try

{

_webApiClient = new HttpClient { BaseAddress = _baseAddress };

if (appendHeader) AppendDefaultHeaders();

var webApiResponse = Task.Run(() => _webApiClient.GetAsync(requestUri)).Result;

var responseContent = webApiResponse.Content.ReadAsStringAsync().Result;

return JsonConvert.DeserializeObject<T>(responseContent);

}

catch (Exception ex) {

throw ex;

}

}

any assistance is greatly appreciated!

网友答案:

async is a keyword that marks a method as a candidate for a complete rewrite by the compiler to support the async/await pattern.

What happens is that the method is split at every point where you use the await keyword internally. If you mark a method as async but don't use await it will complain as either you marked it unnecessary, or you forgot to use await. So that's why you get the compiler errors.

Now, the next bit is to add await to your method, but that means changing it slightly:

  • Spinning up another task just to run a task is one step too many
  • Using .Result on tasks are prone to deadlocks, and this is where await comes in handy

So let's rewrite your method. First we get rid of calls to Task.Result and replace with await:

protected async Task<T> PerformGet<T>(string requestUri, bool appendHeader)
{
    try
    {
        _webApiClient = new HttpClient { BaseAddress = _baseAddress };
        if (appendHeader) AppendDefaultHeaders();
        var webApiResponse = await Task.Run(() => _webApiClient.GetAsync(requestUri));
        var responseContent = await webApiResponse.Content.ReadAsStringAsync();
        return JsonConvert.DeserializeObject<T>(responseContent);
    } 
    catch (Exception ex) {
        throw ex;
    }
}

Then we get rid of the unnecessary task-in-task:

protected async Task<T> PerformGet<T>(string requestUri, bool appendHeader)
{
    try
    {
        _webApiClient = new HttpClient { BaseAddress = _baseAddress };
        if (appendHeader) AppendDefaultHeaders();
        var webApiResponse = await _webApiClient.GetAsync(requestUri);
        var responseContent = await webApiResponse.Content.ReadAsStringAsync();
        return JsonConvert.DeserializeObject<T>(responseContent);
    } 
    catch (Exception ex) {
        throw ex;
    }
}

Then we get rid of the unnecessary try/catch:

protected async Task<T> PerformGet<T>(string requestUri, bool appendHeader)
{
    _webApiClient = new HttpClient { BaseAddress = _baseAddress };
    if (appendHeader) AppendDefaultHeaders();
    var webApiResponse = await _webApiClient.GetAsync(requestUri);
    var responseContent = await webApiResponse.Content.ReadAsStringAsync();
    return JsonConvert.DeserializeObject<T>(responseContent);
}

Then we place the HttpClient object into a using statement:

protected async Task<T> PerformGet<T>(string requestUri, bool appendHeader)
{
    using (var client = new HttpClient { BaseAddress = _baseAddress })
    {
        if (appendHeader) AppendDefaultHeaders(client);
        var response = await client.GetAsync(requestUri);
        var responseContent = await response.Content.ReadAsStringAsync();
        return JsonConvert.DeserializeObject<T>(responseContent);
    }
}

This removes the field, which is usually a bad idea when doing asynchronous work, and makes it a local concept of this method. This also requires a change to the AppendDefaultHeaders method to accept the client that it should add the headers to as a parameter.

网友答案:

You've marked your method async but you are not using await. There is no reason for your method to be async. You can rewrite the definition to be

protected T PerformGet<T>(string requestUri, bool appendHeader)

async essentially says 'In this method, we're going to await an asnyc call'

网友答案:

The reason is you are not awaiting anything as you have .Result at the end of your async calls. Try this

protected async Task<T> PerformGet<T>(string requestUri, bool appendHeader)    
{
    try
    {
        _webApiClient = new HttpClient { BaseAddress = _baseAddress };
        if (appendHeader) AppendDefaultHeaders();
        var webApiResponse = await Task.Run(() => _webApiClient.GetAsync(requestUri));
        var responseContent = await webApiResponse.Content.ReadAsStringAsync();
        return JsonConvert.DeserializeObject<T>(responseContent);
    } 
    catch (Exception ex) {
        throw ex;
    }
}
网友答案:

You can't use await and .Result at the same time. It's one or another. Result will block your thread until the async method is finished, like it would be a synchronous method. await indicates the thread will be moved back to the threadpool while the method is running, and when the method has finished, it will grab another thread to continue the rest of the function. So your function should be:

protected async Task<T> PerformGet<T>(string requestUri, bool appendHeader)
    {
        try
        {
            _webApiClient = new HttpClient { BaseAddress = _baseAddress };
            if (appendHeader) AppendDefaultHeaders();
            var webApiResponse = await Task.Run(() => _webApiClient.GetAsync(requestUri));
            var responseContent = await webApiResponse.Content.ReadAsStringAsync().;
            return JsonConvert.DeserializeObject<T>(responseContent);
        } 
        catch (Exception ex) {
            throw ex;
        }
    }

Also your Task.Run(...) is kinda pointless, just use var webApiResponse = await _webApiClient.GetAsync(requestUri));

网友答案:

Have you tried this:

protected async Task<T> PerformGet<T>(string requestUri, bool appendHeader)
{
    try
    {
        _webApiClient = new HttpClient { BaseAddress = _baseAddress };
        if (appendHeader) AppendDefaultHeaders();
        var webApiResponse = await Task.Run(() => _webApiClient.GetAsync(requestUri));
        var responseContent = await webApiResponse.Content.ReadAsStringAsync();
        return JsonConvert.DeserializeObject<T>(responseContent);
    } 
    catch (Exception ex) {
        throw ex;
    }
}
网友答案:

Based on this:

var webApiResponse = Task.Run(() => _webApiClient.GetAsync(requestUri)).Result;

I would suggest you take a step back and try to understand what async await is trying to do for you. There is a bit of a learning curve, but it will ensure you don't actually make things worse by using it.

相关阅读:
Top